CF1740I Arranging Crystal Balls
这是一个我花了 1.5h 思考出的比标算更优的做法,目前未经过卡常的代码获得了 CF 最优解。
设
我们可以从
那么每次操作即为在某个环上选择相邻两个数分别
对于一个环,设它上面的数依次为
不妨设
设
枚举
之后每次操作对
最少的操作次数即为
设这个环在
可以得到,对于任意
我们可以对每个环事先计算出
因此我们可以依次考虑每个环,对于每个
设
时间复杂度
考虑一个环的
可以使用单调队列在
参考代码:
#include <bits/stdc++.h>
using namespace std;
#define N 1000005
#define LIM 10000005
#define ll long long
#define gc() (P1==P2 && (P2=(P1=buf)+fread(buf,1,LIM,stdin),P1==P2)?EOF:*P1++)
const ll INF=1e18;char buf[LIM],*P1=buf,*P2=buf;
int n,n1,m,c,d,tp,gl,a[N],a1[N],b[N],q[N];
ll ans,w[N],dp[N],tmp[N*2];struct Node {int l,r;ll w;}z[N];
int rd()
{
int res=0;char c=0;while(!isdigit(c)) c=gc();
while(isdigit(c)) res=res*10+(c-48),c=gc();return res;
}
int gcd(int x,int y) {return y?gcd(y,x%y):x;}
int main()
{
n=rd();m=rd();c=rd();d=gcd(n,c);n1=n/d;
for(int i=0;i<n;++i) a1[i]=rd();gl=a1[n-1];
for(int i=0;i<n;++i) a[(i+1)%n]=(a1[(i+1)%n]-a1[i]+m)%m;
ans=INF;for(int i=1;i<m;++i) dp[i]=INF;
for(int i=0,t;i<d;++i)
{
for(int j=0;j<n1;++j)
{
t=(i+1ll*j*c)%n;b[j]=a[t];if(j) b[j]=(b[j]+b[j-1])%m;
if(t+c>=n) gl=(gl-b[j]+m)%m;
}if(b[n1-1]) {printf("-1\n");return 0;}for(int j=0;j<m;++j) w[j]=min(j,m-j);
for(int j=0;j<n1-1;++j) for(int k=0;k<m;++k) t=(b[j]+k)%m,w[k]+=min(t,m-t);
tp=0;z[++tp]=(Node) {0,0,w[1]-w[0]};
for(int j=2;j<m;++j) if(w[j]-w[j-1]!=z[tp].w)
z[tp].r=j-1,z[++tp]=(Node) {j,0,w[j]-w[j-1]};z[tp].r=m-1;
for(int j=0;j<m*2;++j) tmp[j]=INF;
for(int j=1,l,r;j<=tp;++j)
{
q[0]=2;q[1]=1;l=z[j].l;r=z[j].r;
for(int k=l;k<m+r;++k)
{
while(q[0]<=q[1] && q[q[0]]<k-r) ++q[0];
if(k-l<m)
{
while(q[0]<=q[1] && dp[k-l]<=dp[q[q[1]]]+z[j].w*(k-l-q[q[1]]))
--q[1];q[++q[1]]=k-l;
}if(q[0]<=q[1]) tmp[k]=min(tmp[k],dp[q[q[0]]]+w[k-q[q[0]]]);
}
}for(int j=0;j<m;++j) dp[j]=min(tmp[j],tmp[m+j]);
}for(int i=0;i<m;++i) if(gl==1ll*c/d*i%m) ans=min(ans,dp[i]);
if(ans<INF) printf("%lld\n",ans);else printf("-1\n");return 0;
}