1. 程式人生 > 其它 >題解 CF1605E Array Equalizer

題解 CF1605E Array Equalizer

傳送門

首先將 \(a_i\) 變成 \(a_i-b_i\)
發現如果不管 \(a_1\) 的話,需要什麼操作是可以預處理出來的
然後單獨把 \(a_1\) 弄成0,需要什麼操作也是可以預處理出來的
要求最小化操作次數,發現這兩部分中有一些在同一位置的恰好相反的操作是可以消掉的
注意一個事情,若 \(a_1\) 恰好增加(或減少)1的話,其它任意位置需要的額外運算元不超過1
實際上位置 \(i\) 需要的操作是給這個位置加上一個 \(\mu(i)\),可以根據實際意義容斥證明
於是令 \(A\) 為當 \(a_i\) 增加1時需要進行加1操作的集合,\(B\) 為需要減1操作的集合
維護 \(val1\)

\(A\) 中不考慮 \(a_1\) 時的應加次數升序排序
\(sum1\)\(val1\) 的字首和
就會發現當 \(a_1\) 增加 \(x\) 時可以在 \(val1\) 中二分出一個分界點 \(t\)
可以消掉的運算元就是 \(2(sum1_t+x(|A|-t))\)

點選檢視程式碼
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 200010
#define ll long long
//#define int long long

char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
	int ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

int n, q;
int a[N], b[N], t[N];
int cge[N], val1[N], val2[N], val3[N], val4[N], top1, top2, top3, top4;
ll sum1[N], sum2[N], sum3[N], sum4[N], sum, once=1, x;
bool ina[N], inb[N], inc[N], ind[N];

signed main()
{
	n=read();
	for (int i=1; i<=n; ++i) a[i]=read();
	for (int i=1; i<=n; ++i) b[i]=read();
	for (int i=2; i<=n; ++i) a[i]-=b[i];
	for (int i=2; i<=n; ++i) if (a[i]) {
		cge[i]=-a[i];
		for (int j=i*2; j<=n; j+=i) a[j]-=a[i];
		a[i]=0;
	}
	for (int i=2; i<=n; ++i) ++a[i];
	for (int i=2; i<=n; ++i) if (a[i]) {
		++once;
		if (a[i]<0) ina[i]=1;
		else inb[i]=1;
		for (int j=i*2; j<=n; j+=i) a[j]-=a[i];
		a[i]=0;
	}
	for (int i=1; i<=n; ++i) sum+=abs(cge[i]);
	for (int i=1; i<=n; ++i)
		if (ina[i]&&cge[i]<0) val1[++top1]=abs(cge[i]);
		else if (ina[i]&&cge[i]>0) val3[++top3]=abs(cge[i]);
		else if (inb[i]&&cge[i]>0) val2[++top2]=abs(cge[i]);
		else if (inb[i]&&cge[i]<0) val4[++top4]=abs(cge[i]);
	sort(val1+1, val1+top1+1); sort(val2+1, val2+top2+1);
	sort(val3+1, val3+top3+1); sort(val4+1, val4+top4+1);
	for (int i=1; i<=top1; ++i) sum1[i]=sum1[i-1]+val1[i];
	for (int i=1; i<=top2; ++i) sum2[i]=sum2[i-1]+val2[i];
	for (int i=1; i<=top3; ++i) sum3[i]=sum3[i-1]+val3[i];
	for (int i=1; i<=top4; ++i) sum4[i]=sum4[i-1]+val4[i];
	#if 0
	cout<<"val1: "; for (int i=1; i<=top1; ++i) cout<<val1[i]<<' '; cout<<endl;
	cout<<"val2: "; for (int i=1; i<=top2; ++i) cout<<val2[i]<<' '; cout<<endl;
	cout<<"val3: "; for (int i=1; i<=top3; ++i) cout<<val3[i]<<' '; cout<<endl;
	cout<<"val4: "; for (int i=1; i<=top4; ++i) cout<<val4[i]<<' '; cout<<endl;
	cout<<"cge: "; for (int i=1; i<=n; ++i) cout<<cge[i]<<' '; cout<<endl;
	#endif
	q=read();
	while (q--) {
		x=a[1]-read();
		if (x>0) {
			int t1=upper_bound(val3+1, val3+top3+1, x)-val3-1;
			int t2=upper_bound(val4+1, val4+top4+1, x)-val4-1;
			// cout<<"once: "<<once<<endl;
			// cout<<"sum: "<<sum<<endl;
			// cout<<"t: "<<t1<<' '<<t2<<endl;
			// cout<<sum3[t1]+(top3-t1)<<' '<<sum4[t2]+(top4-t2)<<endl;
			printf("%lld\n", sum+1ll*x*once-2ll*(sum3[t1]+x*(top3-t1)+sum4[t2]+x*(top4-t2)));
		}
		else if (x<0) {
			x=abs(x);
			int t1=upper_bound(val1+1, val1+top1+1, x)-val1-1;
			int t2=upper_bound(val2+1, val2+top2+1, x)-val2-1;
			// cout<<"once: "<<once<<endl;
			// cout<<"sum: "<<sum<<endl;
			// cout<<"t: "<<t1<<' '<<t2<<endl;
			printf("%lld\n", sum+1ll*x*once-2ll*(sum1[t1]+x*(top1-t1)+sum2[t2]+x*(top2-t2)));
		}
		else printf("%lld\n", sum);
	}	
	
	return 0;
}