m很小100,一个O(nm)的复杂度
两个手环增加非负整数亮度,等于其中一个增加一个整数亮度(可以为负)
显而易见,最多增加[-m,m]个亮度
考虑O(n)枚举对齐方式,O(m)枚举差距的亮度
亮度增加的时候,维护平方和,只用维护之前的平方和,所有项的和即可
但是每次旋转,初始的对齐位置会发生改变,所以暴力可以O(N^2)
我们只关心初始的平方和
拆开,其实就要求∑ai*bj
由于旋转,所以b倍长,
对应下标差一定,求乘积
把a数组reverse,然后NTT快乐搞定
开始没有注意两个环都可以增亮,,所以只枚举了[0,m],没想到有95pts、。。。
代码:
#include<bits/stdc++.h> #define reg register int #define il inline #define numb (ch^'0') #define int long long using namespace std; typedef long long ll; il void rd(int &x){ char ch;x=0;bool fl=false; while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true); for(x=numb;isdigit(ch=getchar());x=x*10+numb); (fl==true)&&(x=-x); } namespace Miracle{ const int N=100000+5; const int mod=998244353; const int G=3; const int GI=332748118; const int inf=0x3f3f3f3f; int n,m; ll qm(ll x,ll y){ ll ret=1; while(y){ if(y&1) ret=ret*x%mod; x=x*x%mod; y>>=1; } return ret; } int rev[8*N]; ll a[8*N],b[8*N]; void NTT(ll *f,int n,int c){ for(reg i=0;i<n;++i){ if(i<rev[i]) swap(f[i],f[rev[i]]); } for(reg p=2;p<=n;p<<=1){ ll gen; int len=p/2; if(c==1) gen=qm(G,(mod-1)/p); else gen=qm(GI,(mod-1)/p); for(reg l=0;l<n;l+=p){ ll buf=1; for(reg k=l;k<l+len;++k){ ll tmp=buf*f[k+len]%mod; f[k+len]=(f[k]-tmp+mod)%mod; f[k]=(f[k]+tmp)%mod; buf=buf*gen%mod; } } } } void calc(ll *f,ll *g,int n){ NTT(f,n,1),NTT(g,n,1); for(reg i=0;i<n;++i) f[i]=f[i]*g[i]%mod; NTT(f,n,-1); ll inv=qm(n,mod-2); for(reg i=0;i<n;++i) f[i]=f[i]*inv%mod; } int main(){ rd(n);rd(m); ll s1=0,s2=0; ll f1=0,f2=0; for(reg i=0;i<n;++i) scanf("%lld",&a[i]),s1+=a[i],f1+=a[i]*a[i]; for(reg j=0;j<n;++j) scanf("%lld",&b[j]),s2+=b[j],f2+=b[j]*b[j]; reverse(a,a+n); for(reg j=n;j<=2*n-1;++j) b[j]=b[j-n]; int lp; int len=0; for(lp=2*n+2*n,len=1;len<lp;len<<=1); for(reg i=0;i<len;++i){ rev[i]=(rev[i>>1]>>1)|((i&1)?(len>>1):0); } // for(reg i=0;i<len;++i) printf("%d ",a[i]);puts(""); // for(reg i=0;i<len;++i) printf("%d ",b[i]); calc(a,b,len);// ans is in array a // cout<<" len "<<len<<endl; // for(reg i=0;i<len;++i){ // cout<<a[i]<<" "; // }cout<<endl; ll ans=inf; for(reg i=0;i<n;++i){ ll su=0,sf=0; su=s1-s2; sf=f1+f2-2*a[i+n]; ans=min(ans,sf); for(reg j=1;j<=m;++j){ sf+=2*su+n; su+=n; ans=min(ans,sf); } su=s1-s2; sf=f1+f2-2*a[i+n]; for(reg j=1;j<=m;++j){ sf-=2*su-n; su-=n; ans=min(ans,sf); } } printf("%lld",ans); return 0; } } signed main(){ Miracle::main(); return 0; } /* Author: *Miracle* Date: 2019/1/10 16:53:09 */