【数学思考】Codeforces Round #754 (Div. 2)E 待写


https://codeforces.com/contest/1605/problem/E

题意:对数组 [公式] 进行若干次操作,变换为 [公式] 数组。操作如下:

  • 选择一个 [公式] ,对所有 [公式] 的倍数 [公式] 施以 [公式]
  • 选择一个 [公式] ,对所有 [公式] 的倍数 [公式] 施以 [公式]

回答 [公式] 次询问,每次询问改变 [公式] ,并求至少需要几次操作,才能将 [公式] 变为 [公式]

题意翻译来源+某大佬的题解

我们可以考虑如果不改变b1那对于一个数列考虑

设置所有bi = bi-ai,ai = 0 发现不影响答案

然后我们最优的策略一定是先改变1然后2。。。

我们考虑发生了什么就可以O(n)处理

官方题解对于该方面考虑的就很好

然后我们发现对于每一个位置的改变都是一个数学式子,式子里包含若干bi*系数+系数*b1(未知的变量)

然后推一推就可以发现关于第一个位置的系数是莫比乌斯函数

所以我们将这样的系数加入数列。然后对于b1二分,(若b1前系数为+1我们将整个式子*-1由于求绝对值故不改变最后的数)。二分出来对于小于-b1的和大于-b1的分别考虑即完成对绝对值的处理。答案就出来了

语文不太好说得很抽象具体可以看官方题解,写得很好。

#include 

using namespace std;
typedef long long ll;
const int maxn = 2e5 + 5;
int n;
int a[maxn], b[maxn];
ll qz[maxn], qzh[maxn], tot;
ll c[maxn], mob[maxn];
int pri[maxn], cnt;
bool nop[maxn];
void init() {
    nop[1] = 1;
    mob[1] = 1;
    for (int i = 2; i <= n; i++) {
        if (!nop[i]) {
            pri[++cnt] = i;
            mob[i] = -1;
        }
        for (int j = 1; j <= cnt && 1ll * i * pri[j] <= n; j++) {
            nop[i * pri[j]] = 1;
            if (i % pri[j] == 0)
                break;
            mob[i * pri[j]] = -mob[i];
        }
    }
}
ll sum(int l, int r) {
    if (l > r)
        return 0;
    return qzh[r] - qzh[l - 1];
}
int main() {
    scanf("%d", &n);
    init();
    for (int i = 1; i <= n; i++) {
        scanf("%d", &a[i]);
    }
    for (int i = 1; i <= n; i++) {
        scanf("%d", &b[i]);
    }
    for (int i = 1; i <= n; i++)
        c[i] = b[i] - a[i];
    c[1] = 0;
    ll ans = 0;
    for (int i = 1; i <= n; i++) {
        for (int j = i + i; j <= n; j += i) {
            c[j] -= c[i];
        }
    }
    for (int i = 1; i <= n; i++) {
        if (mob[i] == 0)
            ans += llabs(c[i]);
        else if (mob[i] == -1)
            qz[++tot] = -c[i];
        else
            qz[++tot] = c[i];
    }
    sort(qz + 1, qz + 1 + tot);
    for (int i = 1; i <= tot + 1; i++)
        qzh[i] = qzh[i - 1] + qz[i];
    int q;
    scanf("%d", &q);
    while (q--) {
        int x;
        scanf("%d", &x);
        x -= a[1];
        int wz = lower_bound(qz + 1, qz + 1 + tot, -x) - qz;
        ll nans = sum(wz, tot) + 1ll * (tot - wz + 1) * x;
        nans -= sum(1, wz - 1) + 1ll * (wz - 1) * x;
        printf("%lld\n", ans + nans);
    }
    return 0;
}