2020牛客NOIP赛前集训营-普及组(第五场)

A T1 购物

分析

由于是买 送一,所以我们考虑买 只需要 次花钱的购买。那么可以把 个物品分成很多段,每段的长度为 ,然后处理一下边角就好了。

代码

#include<bits/stdc++.h>
using namespace std;
int read() {int x;scanf("%d",&x);return x;}
int solve(int a,int b,int c) {
    return (a / (b + 1) * b + (a % (b + 1))) * c;
}
int main() {
    int T = read();
    while(T--) {
        int n,k,x;
        n = read();k = read();x = read();
        cout << solve(n,k,x) << endl; 
    }
}

B T2 交换

分析

对于环的分析,我们习惯于破环成链。这样在一个序列上也可以表示所有环了。那么我们就在这个长度为 的序列上找到最长的全为 的子串就好了。需要处理一下子串的长度大于 的情况。

代码

#include<bits/stdc++.h>
using namespace std;
int read() {int x;scanf("%d",&x);return x;}
const int N = 210000;
char ch[N];
int main() {
    scanf("%s",ch + 1);
    int n = strlen(ch + 1),ans = 0;
    for(int i = 1;i < n;i++) ch[i + n] = ch[i];
    for(int i = 1,last = 0;i < n * 2;i++) {
        if(ch[i] == '1' && ch[i - 1] != '1') last = i;
        if(ch[i] == '1' && i - last + 1 <= n) ans = max(ans,i - last + 1);
    } 
    cout << ans << endl;
}

C T3 最少移动

分析

我们发现任意操作都不会改变 的,也就是总和不变。那么最后每个点的权值一定是 的,那么 的就可以输出 。因为要改变 就必须操作 所以我们可以从一个端点 扫一遍就好了。

代码

#include<bits/stdc++.h>
using namespace std;
int read() {int x;scanf("%d",&x);return x;}
#define ll long long
const int N = 1e5 + 100;
int a[N];ll s;
int main() {
    int T = read();
    while(T--) {
        s = 0;int n = read();
        for(int i = 1;i <= n;i++) {
            a[i] = read();
            s += a[i];
        }
        ll ans = 0;
        if(s % n) {printf("-1\n");continue;}
        for(int i = 1;i <= n;i++) {
            int sum = s / n - a[i];
            a[i + 1] -= sum;
            ans += abs(sum);
        }
        cout << ans << endl; 
    }
}

D T4 飞行棋

分析

我们定义 为到节点 的期望回合数,那么 。由于 时每个节点只有 的概率转移到 剩下的 也会转移到另一个 节点。所以 时,每个 是相同的。 。那么当 时,直接转移就好了,用前缀和维护一下,时间复杂度为 。注意一下掷出来 时,并不改变回合数。

代码

#include<bits/stdc++.h>
using namespace std;
int read() {int x;scanf("%d",&x);return x;}
#define ll long long
const int N = 1e5 + 100;
double f[N],s[N];
int main() {
    int T = read();
    while(T--) {
        int n = read(),d = read();s[0] = f[0] = 1;
        for(int i = 1;i < d;i++) s[i] = d - 1,f[i] = f[i - 1] + s[i];
        for(int i = d;i <= n;i++) {
            s[i] = (f[i - 1] - f[i - d] + d - 1) / (1.0 * d) + s[i - d] / (1.0 * d);
            f[i] = f[i - 1] + s[i];
        }
        printf("%.2f\n",s[n]);
    }
}