[AH2017/HNOI2017]礼物

题解:

水题

化简一波式子会发现就是个二次函数再加上一个常数

而只有常数中的-2sigma(xiyi)是随移动而变化的

所以只要o(1)求出二次函数最大值然后搞出sigma(xiyi)就可以了

这个东西显然只要将一个倒序相乘就可以了

被这个m要乘2坑了一波。。。调了半天才过样例

代码:

#include <bits/stdc++.h>
using namespace std;
#define N 200000
#define dob complex<double>
const double pi=acos(-1.0);
int r[N],sum[N],n,m,k,l;
dob a[N],b[N];
void fft(dob *a,int o)
{
    for (int i=0;i<n;i++)
      if (i>r[i]) swap(a[i],a[r[i]]);
    for (int i=1;i<n;i*=2)
    {
        dob wn(cos(pi/i),sin(pi*o/i)),x,y;
        for (int j=0;j<n;j+=(i*2))
        {
            dob w(1,0);
            for (int k=0;k<i;k++,w*=wn)
            {
                x=a[j+k]; y=w*a[i+j+k];
                a[j+k]=x+y,a[i+j+k]=x-y;
            }
        }
    }
}
void query()
{
    for (n = 1; n <= m; n <<= 1) l++;
    for (int i=0;i<n;i++) r[i]=(r[i/2]/2)|((i&1)<<(l-1));
    fft(a,1),fft(b,1);
    for (int i=0;i<n;i++) a[i]*=b[i];
    fft(a,-1);
    for (int i=0;i<=m*2+10;i++) sum[i]=(a[i].real()/n+0.5);
}
int main()
{
  freopen("noip.in","r",stdin);
  freopen("noip.out","w",stdout);
  std::ios::sync_with_stdio(false);
  cin>>m>>k; int x,now=0,ans=0;
  for (int i=0;i<m;i++)
  {
    cin>>x; now+=x; ans+=x*x; a[i]=x;
  }
  for (int i=m-1;i>=0;i--)
  {
    cin>>x; now-=x; ans+=x*x; b[i]=x;  
  }
  int y=-now/m;
  int minn=1e9;
  for (int i=y-1;i<=y+1;i++)
    minn=min(m*i*i+2*i*now,minn);
  ans+=minn;
  int tmp=m; m*=2;
  query();
  m=tmp;
  int maxn=sum[m-1];
  for (int i=m;i<2*m;i++) maxn=max(sum[i]+sum[i-m],maxn);
  ans-=2*maxn;
  cout<<ans<<endl;
  return 0;
} 
原文地址:https://www.cnblogs.com/yinwuxiao/p/8798929.html