NC20122. [HNOI2017]礼物
描述
我的室友最近喜欢上了一个可爱的小女生。马上就要到她的生日了,他决定买一对情侣手环,一个留给自己,一个送给她。每个手环上各有 n 个装饰物,并且每个装饰物都有一定的亮度。
但是在她生日的前一天,我的室友突然发现他好像拿错了一个手环,而且已经没时间去更换它了!他只能使用一种特殊的方法,将其中一个手环中所有装饰物的亮度增加一个相同的自然数 c(即非负整数)。并且由于这个手环是一个圆,可以以任意的角度旋转它,但是由于上面装饰物的方向是固定的,所以手环不能翻转。需要在经过亮度改造和旋转之后,使得两个手环的差异值最小。
输入描述
输入数据的第一行有两个数n, m,代表每条手环的装饰物的数量为n,每个装饰物的初始亮度小于等于m。
接下来两行,每行各有n个数,分别代表第一条手环和第二条手环上从某个位置开始逆时针方向上各装饰物的亮度。
输出描述
输出一个数,表示两个手环能产生的最小差异值。注意在将手环改造之后,装饰物的亮度
可以大于 m。
示例1
输入:
5 6 1 2 3 4 5 6 3 3 4 5
输出:
1
说明:
【样例解释】C++14(g++5.4) 解法, 执行用时: 471ms, 内存消耗: 109536K, 提交时间: 2020-03-20 18:42:13
#include<bits/stdc++.h> typedef long long ll; typedef double db; using namespace std; const ll N=2e6+1e5; const ll MAXN=N; const db pi=acos(-1.0);//π ll n,m; struct cp{//复数,x是实部,y是虚部 db x,y; cp(){x=y=0;} cp(db xx,db yy){x=xx,y=yy;} }f[N],g[N],ans[N]; //复数运算 cp operator + (cp a,cp b){ return cp(a.x+b.x,a.y+b.y); }cp operator - (cp a,cp b){ return cp(a.x-b.x,a.y-b.y); }cp operator * (cp a,cp b){ return cp(a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x); }void FFT(ll n,cp *a,ll t){//t:1表示系数转点值,-1则相反 if(n<=1)return;//递归边界 ll mid=n>>1; cp a1[mid],a2[mid]; //按系数奇偶性分出 a1, a2 for (ll i=0;i<=mid-1;i++){ a1[i]=a[i<<1]; a2[i]=a[i<<1|1]; }//递归 FFT(mid,a1,t); FFT(mid,a2,t); cp w1(cos(pi/mid),t*sin(pi/mid)),w(1,0),wt; //w1:就是 wn,t的运用使IFFT时能乘上共轭复数 //w是第一个单位根,就是实数 1 for (ll i=0;i<=mid-1;i++){ wt=w*a2[i]; //代入公式 a[i]=a1[i]+wt;//注意 a1[i] 表示是 n/2 次单位根 a[i+mid]=a1[i]-wt; w=w*w1;//下一个单位根 } } ll A[MAXN],B[MAXN],ANS[MAXN]; ll mult(ll n,ll m){ for (ll i=0;i<=n;i++) f[i].x=A[i]; for (ll i=0;i<=m;i++) g[i].x=B[i]; ll k=1; while(k<=n+m)k<<=1;//记得吗?我们能处理的必须是2的整数次幂 FFT(k,f,1); FFT(k,g,1); for (ll i=0;i<=k;i++) ans[i]=f[i]*g[i]; FFT(k,ans,-1); for (ll i=0;i<=n+m;i++){ ANS[i]=(ll)(ans[i].x/k+0.5); //cout<<ans[i].x<<endl; } } ll suma=0,sumb=0; int main(){ cin>>n>>m; for (int i=0;i<n;i++) { cin>>A[i]; suma+=A[i]; } for (ll i=0;i<n;i++){ cin>>B[n-1-i]; sumb+=B[n-1-i]; B[2*n-i-1]=B[n-i-1]; } mult(n-1,2*n-1); ll mc=0; for (ll i=n;i<=2*n-1;i++)//cout<<ANS[i]<<' '; mc=max(mc,ANS[i]); //cout<<mc<<endl; ll z=0; for (ll i=0;i<n;i++) z+=A[i]*A[i]+B[i]*B[i]; //cout<<z<<endl; z-=2*mc; //cout<<z<<endl; ll r=abs(suma-sumb)/n; ll rr=r+1; //cout<<r<<endl; z+=min(2*-abs(suma-sumb)*r+n*r*r,2*-abs(suma-sumb)*rr+n*rr*rr); cout<<z<<endl; return 0; }
C++ 解法, 执行用时: 82ms, 内存消耗: 17144K, 提交时间: 2022-04-26 09:17:26
#include <bits/stdc++.h> using namespace std; typedef long long ll; const double pi=acos(-1.0); struct node{ double x,y; node(double a=0,double b=0):x(a),y(b){} node operator + (const node &b) const{return node(x+b.x,y+b.y);} node operator - (const node &b) const{return node(x-b.x,y-b.y);} node operator * (const node &b) const{return node(x*b.x-y*b.y,x*b.y+y*b.x);} }a[500010],b[500010]; int rev[500010],ans[500010]; void fft(node F[],int len,int kk=1){ for(int i=0;i<len;i++) if(i<rev[i]) swap(F[i],F[rev[i]]); for(int i=1;i<len;i<<=1){ node unit=node(cos(pi/i),sin(kk*pi/i)); for(int j=0;j<len;j+=(i<<1)){ node w(1,0); for(int k=0;k<i;k++,w=w*unit){ node x=F[j+k],y=w*F[j+k+i]; F[j+k]=x+y; F[i+j+k]=x-y; } } } } int main() { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int n,m; ll A=0,B=0,C=0; cin>>n>>m; A=n; for(int i=0;i<n;i++){ cin>>a[i].x; a[i+n].x=a[i].x; } for(int i=0;i<n;i++) cin>>b[n-1-i].x; for(int i=0;i<n;i++){ int aa=a[i].x,bb=b[n-1-i].x; B+=aa-bb; C+=aa*aa+bb*bb; } B*=2; int len=1,bit=0; while(len<=3*n){ len<<=1; bit++; } for(int i=0;i<len;i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<(bit-1)); fft(a,len); fft(b,len); for(int i=0;i<len;i++) a[i]=a[i]*b[i]; fft(a,len,-1); ll tmp=-0x3f3f3f3f3f3f3f3f; for(int i=n-1;i<=2*n-1;i++) tmp=max(tmp,(ll)(a[i].x/len+0.5)); C-=2*tmp; int l=(-1.0*B/(2*A)),r=ceil(-1.0*B/(2*A)); cout<<max(0ll,min(1ll*A*l*l+B*l+C,1ll*A*r*r+B*r+C))<<"\n"; return 0; }