题目大意
有两个长度为(n)((nleq5*10^4))的数列(x_1,x_2,...,x_n)和(y_1,y_2,...,y_n),两个数列里的数都不超过(m)((mleq100))
现在可以进行“(1)把(x)中的所有数同时加上一个值”和“(i<n)时,((2)x_i)变成(x_{i+1});(i=n)时,(x_i)变成(x_1)”这两种操作
操作任意次,使(Sigma_{i=1}^{n}{(x_i-y_i)^2})最小
题解
设(1)操作加上的值为(k),(2)操作执行了(j)次;定义(add(a,b))在(a+bleq n)时为(a+b),否则为(a+b-n)
那么就是要选出合适的(k,j),使(Sigma_{i=1}^{n}{(x_i+k-y_{add(i,j)})^2})最小
该式=(Sigma_{i=1}^{n}{(x_i^2+k^2-y_{add(i,j)}^2+2*x_i*k-2*x_i*y_{add(i,j)}-2*k*y_{add(i,j)})})
=((Sigma_{i=1}^{n}x_i^2)+(Sigma_{i=1}^{n}y_i^2)+n*k^2+(Sigma_{i=1}^{n}{(2*x_i*k-2*x_i*y_{add(i,j)}-2*k*y_{add(i,j)})}))
其中((Sigma_{i=1}^{n}x_i^2)+(Sigma_{i=1}^{n}y_i^2))是定值,要让剩下的部分(n*k^2+(Sigma_{i=1}^{n}{(2*x_i*k-2*x_i*y_{add(i,j)}-2*k*y_{add(i,j)})}))更小
该式=(n*k^2+(Sigma_{i=1}^{n}{(2*k*(x_i-y_{add(i,j)})-2*x_i*y_{add(i,j)}}))
=(n*k^2+(Sigma_{i=1}^{n}{2*k*(x_i-y_{add(i,j)})})-(Sigma_{i=1}^{n}{2*x_i*y_{add(i,j)}}))
=(n*k^2+2*k*((Sigma_{i=1}^{n}{x_i})-(Sigma_{i=1}^{n}{y_i}))-(Sigma_{i=1}^{n}{2*x_i*y_{add(i,j)}}))
将它分成两部分,第一部分是(n*k^2+2*k*((Sigma_{i=1}^{n}{x_i})-(Sigma_{i=1}^{n}{x_i}))),第二部分是((Sigma_{i=1}^{n}{2*x_i*y_{add(i,j)}}))
第一部分只和(k)有关,第二部分只和(j)有关
那就可以分别算出(k)为(-m)到(m)时第一部分的取值,分别算出(j)为(0)到(n-1)时第二部分的取值,再枚举(k,j)的值
发现第二部分是个卷积式,算这部分的时间复杂度围为(Theta(n*log n))
总时间复杂度是(Theta(n*log n+n*m))
代码
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<iomanip>
#include<iostream>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<vector>
#define rep(i,x,y) for(register int i=(x);i<=(y);++i)
#define dwn(i,x,y) for(register int i=(x);i>=(y);--i)
#define maxn 50010
#define maxm (maxn*6)
#define inf 2147483647
#define LL long long
using namespace std;
int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)&&ch!='-')ch=getchar();
if(ch=='-')f=-1,ch=getchar();
while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
return x*f;
}
void write(int x)
{
if(x==0){putchar('0'),putchar('
');return;}
int f=0;char ch[20];
if(x<0)putchar('-'),x=-x;
while(x)ch[++f]=x%10+'0',x/=10;
while(f)putchar(ch[f--]);
putchar('
');
return;
}
const LL mod = 998244353;
int ans,m,n,fakeans[maxn],x[maxn],y[maxn],sumx,sumy,ans2,a[maxm],b[maxm],nown,len,r[maxm];
int mul(int x,int y){int res=1;while(y){if(y&1)res=(LL)res*(LL)x%mod;x=(LL)x*(LL)x%mod,y>>=1;}return res;}
void dnt(int * c,int f)
{
rep(i,0,nown-1){r[i]=(r[i>>1]>>1)|((i&1)<<(len-1));}
rep(i,0,nown-1){if(i<r[i])swap(c[i],c[r[i]]);}
for(int i=1;i<nown;i<<=1)
{
int wn=mul(3,(mod-1)/(i<<1)),xx,yy;
if(f==-1)wn=mul(wn,mod-2);
for(int j=0;j<nown;j+=(i<<1))
{
int w=1;
rep(k,0,i-1)xx=c[j+k]%mod,yy=(LL)w*(LL)c[j+i+k]%mod,c[j+k]=(xx+yy)%mod,c[j+i+k]=(xx-yy+mod)%mod,w=(LL)w*(LL)wn%mod;
}
}
if(f==-1){int inv=mul(nown,mod-2);rep(i,0,nown-1)c[i]=(LL)c[i]*(LL)inv%mod;}
}
int main()
{
n=read(),m=read();
rep(i,1,n)x[i]=read(),sumx+=x[i],ans2+=x[i]*x[i];
rep(i,1,n)y[i]=read(),sumy+=y[i],ans2+=y[i]*y[i];
rep(i,0,n-1)a[i]=x[i+1];
rep(i,n,(n<<1)-1)a[i]=x[i-n+1];
rep(i,0,n)b[i]=y[n-i]*2;
for(nown=1,len=0;nown<(n+n+n-1);nown<<=1)len++;
dnt(a,1),dnt(b,1);
rep(i,0,nown-1)a[i]=(LL)a[i]*(LL)b[i]%mod;
dnt(a,-1);
rep(i,0,n-1)fakeans[i]=a[i+n-1];
ans=inf;
rep(k,-m,m)rep(j,0,n-1)ans=min(ans,2*k*(sumx-sumy)+n*k*k-fakeans[j]);
write(ans+ans2);
return 0;
}
/*
5 6
1 2 3 4 5
6 3 3 4 5
*/
一些感想
还有一百天左右!