Array Equalizer
[Link](Problem - E - Codeforces)
题意
给你两个数组 a , b a,b a,b,两个操作 1 : 1: 1: 选择一个 i i i将 a a a中 i i i和 i i i的倍数都加 1 1 1 2 : 2: 2: 选择一个 i i i将 a a a中 i i i和 i i i的倍数都减 1 1 1。现在 b 1 b_1 b1不知道是多少,给你 q q q次询问,每次给你一个 b 1 b_1 b1,问你最少操作多少次可以将, a a a变成 b b b。
思路
发现每次给你 b 1 b_1 b1后从前往后对于每个位置 i i i你的操作都是确定的,但是数据范围太大,如果暴力的从前往后遍历的话复杂度是 O ( n 2 ) O(n^2) O(n2)的,需要优化一下。
我们将 [ 2 , n ] [2,n] [2,n]的每个 b i b_i bi都变成 b i = b i − a i b_i=b_i-a_i bi=bi−ai, a i a_i ai都变成零,对于每次询问加入的 b 1 b_1 b1也仿照上面假设 b i bi bi操作完为 x x x,我们将操作定义为少就加多就减。
首先 a 1 a_1 a1要变成 x x x,所以位置一要操作 x x x,则 a 2 = x , a 2 → b 2 a_2=x,a_2\to b_2 a2=x,a2→b2,所以位置二要做操作 b 2 − x b_2-x b2−x,则 a 3 = x , a 3 → b 3 a_3=x,a_3\to b_3 a3=x,a3→b3,所以位置三要做操作 b 3 − x b_3-x b3−x,则 a 4 = x + b 2 − x , a 4 → b 4 a_4=x+b_2-x,a_4\to b_4 a4=x+b2−x,a4→b4,所以位置四要做操作 b 4 − b 2 . . . b_4-b_2\ ... b4−b2 ...
因此在某个位置 i i i做的操作即 m u i x + d i mu_ix+d_i muix+di,因此我们要最小化 ∑ ∣ m u i x + d i ∣ \sum|mu_ix+d_i| ∑∣muix+di∣,发现有奇数个质因子的时候是 − 1 -1 −1,偶数个的时候是 1 1 1,其他 0 0 0,则 m u i mu_i mui为莫比乌斯函数。
那么对于 ∑ ∣ m u i x + d i ∣ \sum|mu_ix+d_i| ∑∣muix+di∣算贡献可以分为三种情况
- m u i = = 0 mu_i==0 mui==0,我们直接将答案加进去即可,
- m u i = = − 1 mu_i==-1 mui==−1,我们将原式取反就等价与 m u i = = 1 mu_i==1 mui==1的情况了
- m u i = = 1 mu_i==1 mui==1,对于这样的情况我们发现将所有的 d i d_i di排序以后具有二段性,即某个 j j j前面 d i < − x d_i<-x di<−x后面 d i > = − x d_i>=-x di>=−x,因此我们每次二分临界点,前缀和一下直接算贡献即可。
复杂度为 O ( q l o g n ) O(qlogn) O(qlogn)
Code
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <set>
#include <queue>
#include <vector>
#include <map>
#include <bitset>
#include <unordered_map>
#include <cmath>
#include <stack>
#include <iomanip>
#include <deque>
#include <sstream>
#define x first
#define y second
#define debug(x) cout<<#x<<":"<<x<<endl;
using namespace std;
typedef long double ld;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef unsigned long long ULL;
const int N = 1e6 + 10, M = 2 * N, INF = 0x3f3f3f3f, mod = 1e9 + 7;
const double eps = 1e-8, pi = acos(-1), inf = 1e20;
#define tpyeinput int
inline char nc() {static char buf[1000000],*p1=buf,*p2=buf;return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;}
inline void read(tpyeinput &sum) {char ch=nc();sum=0;while(!(ch>='0'&&ch<='9')) ch=nc();while(ch>='0'&&ch<='9') sum=(sum<<3)+(sum<<1)+(ch-48),ch=nc();}
int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
int h[N], e[M], ne[M], w[M], idx;
void add(int a, int b, int v = 0) {
e[idx] = b, w[idx] = v, ne[idx] = h[a], h[a] = idx ++;
}
int n, m, k;
LL a[N], b[N], d[N];
int mu[N], primes[N], cnt;
LL sum[N];
bool st[N];
vector<LL> ve;
void get(int n) {
mu[1] = 1;
for (int i = 2; i <= n; i ++) {
if (!st[i]) {
primes[cnt ++] = i;
mu[i] = -1;
}
for (int j = 0; primes[j] <= n / i; j ++) {
st[primes[j] * i] = true;
if (i % primes[j] == 0) {
mu[primes[j] * i] = 0;
break;
}
mu[primes[j] * i] = mu[i] * -1;
}
}
}
LL query(LL l, LL r) {
if (r < 0) return 0;
if (l > ve.size() - 1) return 0;
if (l) return sum[r] - sum[l - 1];
return sum[r];
}
int main() {
ios::sync_with_stdio(false), cin.tie(0);
get(1000000);
cin >> n;
for (int i = 1; i <= n; i ++) cin >> a[i];
for (int i = 1; i <= n; i ++) cin >> b[i], d[i] = b[i] - a[i];
d[1] = 0;
for (int i = 1; i <= n; i ++) {
LL x = d[i];
for (int j = i + i; j <= n; j += i) d[j] -= x;
}
LL res = 0;
for (int i = 1; i <= n; i ++) {
if (!mu[i]) res += abs(d[i]);
else if (mu[i] == -1) ve.push_back(-d[i]);
else ve.push_back(d[i]);
}
sort(ve.begin(), ve.end());
sum[0] = ve[0];
for (int i = 1; i < ve.size(); i ++) sum[i] = sum[i - 1] + ve[i];
int T;
cin >> T;
while (T -- ) {
LL x; cin >> x;
x -= a[1];
int l = 0, r = ve.size() - 1;
while (l < r) {
int mid = l + r >> 1;
if (ve[mid] >= -x) r = mid;
else l = mid + 1;
}
if (ve[l] < -x) l ++;
LL ans = query(l, ve.size() - 1) + x * (ve.size() - l) - query(0, l - 1) - l * x;
cout << res + ans << endl;
}
return 0;
}
本文介绍了一种解决数组操作问题的方法,通过将问题转化为莫比乌斯函数和区间操作,利用二分查找技巧减少复杂度,实现对数组a进行最少操作使其与b匹配的高效求解。关键在于理解莫比乌斯函数在操作优化中的作用,以及如何利用二段性特征进行贡献计算。

被折叠的 条评论
为什么被折叠?



