Codeforces 1740I - Arranging Crystal Balls

(注:默认下标 1-indexed)

考虑一个数组被清零的充要条件:记 \(b_i=a_{i}-a_{(i+n-2)\bmod n+1}\),那么最终 \(a_i=0\) 当且仅当 \(b_i=0\)\(a_1=0\)

思考一次操作的影响:假设我们对 \([x,x+k-1]\) 这段环上的区间进行了 \(+v\),那么相当于是令 \(b_x\)\(v\)\(b_{x+k}\)\(v\)。同时如果这段区间经过了 \(1\),那么令 \(a_1\)\(v\)。考虑在 \(i\)\((i+k-1)\bmod n+1\) 之间连一条边,这样显然图会形成若干个环。每个环是独立的,并且由于我们要让 \(b_i\) 清零,所以钦定了环上一条边进行 \(+1\) 的次数之后,每条边进行 \(+1\) 的次数就确定了,这样总代价可以用 \(\sum \min(c_i,m-c_i)\) 来计算总代价,同时此次操作对 \(a_1\) 的影响也是可以计算的。

这样就有一个很显然的 DP 模型:\(dp_{i,j}\) 表示考虑了前 \(i\) 个环,目前 \(a_1=j\) 的最小代价,由于代价关于我们钦定的那条边的函数实际上是一个分段函数,且每一段都是一个一次函数,因此可以单调队列优化。总复杂度 \(\dfrac{n}{len}·m·len=nm\),其中 \(len\) 是环长。

代码咕了,明天再写。

upd:咕完了。

const int MAXN=1e6;
const ll INF=0x3f3f3f3f3f3f3f3fll;
int n,m,k,a[MAXN+5],b[MAXN+5],vis[MAXN+5];ll dp[MAXN+5];
int main(){
	scanf("%d%d%d",&n,&m,&k);
	for(int i=0;i<n;i++)scanf("%d",&a[i]);
	for(int i=0;i<n;i++)b[i]=(a[i]-a[(i+n-1)%n]+m)%m;
//	for(int i=0;i<n;i++)printf("%d%c",b[i]," \n"[i==n-1]);
	memset(dp,63,sizeof(dp));dp[a[0]]=0;
	for(int i=0;i<n;i++)if(!vis[i]){
		vector<int>seq,val;
		for(int j=i;!vis[j];j=(j+k)%n)seq.pb(j),vis[j]=1;
		seq.pb(seq[0]);val.resize(seq.size(),0);
		int sd=0;for(int j=1;j<seq.size();j++)sd=(sd+b[seq[j]])%m;
		if(sd)return puts("-1"),0;
		for(int j=2;j<seq.size();j++)val[j]=(val[j-1]-b[seq[j-1]]+m)%m;
		static ll ndp[MAXN+5];
		for(int j=0;j<m;j++)ndp[j]=INF;
		int A=0,B=0;
		for(int j=1;j<seq.size();j++)
			if(seq[j-1]==0||(seq[j-1]>seq[j]&&seq[j]!=0))
				A++,B=(B+val[j])%m;
		static ll difa[MAXN+5],difb[MAXN+5];
		auto add=[&](int l,int r,int a,int b){
//			printf("[%d,%d] %dx+%d\n",l,r,a,b);
			difa[l]+=a;difa[r+1]-=a;difb[l]+=b;difb[r+1]-=b;
		};
		for(int j=0;j<=m;j++)difa[j]=difb[j]=0;
		for(int j=1;j<seq.size();j++){
			int l=(m-val[j])%m,r=(m+(m>>1)-val[j])%m;
			if(l<=r)add(l,r,1,-l);
			else add(l,m-1,1,-l),add(0,r,1,m-l);
			if(m!=2){
				l=(m+(m>>1)+1-val[j])%m;r=(m-1-val[j])%m;
				if(l<=r)add(l,r,-1,r+1);
				else add(l,m-1,-1,r+1+m),add(0,r,-1,r+1);
			}
		}
		for(int j=1;j<=m;j++)difa[j]+=difa[j-1],difb[j]+=difb[j-1];
		for(int l=0,r;l<m;l=r){
			r=l;while(r<m&&mp(difa[r],difb[r])==mp(difa[l],difb[l]))++r;
			static bool vis[MAXN+5];for(int j=0;j<m;j++)vis[j]=0;
			for(int j=0;j<m;j++)if(!vis[j]){
				vector<int>vec;
				for(int k=j;!vis[k];k=(k+A)%m)vis[k]=1,vec.pb(k);
				int tmp=vec.size();
				for(int k=0;k<tmp;k++)vec.pb(vec[k]);
				static pair<ll,int> q[MAXN*2+5];int fr=1,tl=0;
				for(int k=0;k<vec.size();k++){
					while(fr<=tl&&q[fr].se<=k-(r-l))++fr;
					ll val=dp[(vec[k]-1ll*A*l%m-B+m+m)%m]-1ll*difa[l]*k;
					while(fr<=tl&&q[tl].fi>val)--tl;
					q[++tl]=mp(val,k);
					if(fr<=tl)chkmin(ndp[vec[k]],q[fr].fi+1ll*difa[l]*(l+k)+difb[l]);
				}
			}
		}
		for(int j=0;j<m;j++)dp[j]=ndp[j];
	}
	printf("%lld\n",(dp[0]==INF)?-1:dp[0]);
	return 0;
}
posted @ 2023-05-26 23:20  tzc_wk  阅读(42)  评论(2编辑  收藏  举报