并不对劲的bzoj4827:loj2020:p3723:[AHOI/HNOI2017]礼物
题目大意
有两个长度为\(n\)(\(n\leq5*10^4\))的数列\(x_1,x_2,...,x_n\)和\(y_1,y_2,...,y_n\),两个数列里的数都不超过\(m\)(\(m\leq100\))
现在可以进行“(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+b\leq 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('\n');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('\n');
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
*/
一些感想
还有一百天左右!