bzoj4827: [Hnoi2017]礼物

链接

  http://www.lydsy.com/JudgeOnline/problem.php?id=4827

题解

  裸的 FFT ,但是我调了一下午(虽然最后1A),我码力真的是弱爆了。
  根据题意,可以直接写出式子
  

ans=i=1n(ai+dbi+x)2

  拆开搞一搞就行了

题外话

  拆开之后,除了和 d 有关的哪些项的预处理都是O(n) O(nlogn) 的,但是和 c 有关的项是O(m)的,这就受到了数据规模中 m 大小的限制,但是容易发现和c有关的项正好是一个二次函数,也就是抛物线,这个其实可以直接用初中的知识求个最值,这样复杂度就成 O(1) 了。(我只是口胡下,自己并没有这么干)

代码

//FFT
#include <cstdio>
#include <cmath>
#include <algorithm>
#define maxn (262144+10)
using namespace std;
int N, M, up, R[maxn], ans;
const double pi=acos(-1);
struct com
{
    double x, y;
    com(double x, double y):x(x),y(y){}
    com(){};
}a[maxn], b[maxn], c[maxn];
inline com operator+(com a, com b){return com(a.x+b.x,a.y+b.y);}
inline com operator-(com a, com b){return com(a.x-b.x,a.y-b.y);}
inline com operator*(com a, com b){return com(a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x);}
inline void fft(com *a, int n, int opt)
{
    int i, j, k; com wn, w, x, y;
    for(i=0;i<n;i++)if(i>R[i])swap(a[i],a[R[i]]);
    for(i=1;i<n;i<<=1)
    {
        wn=com(cos(pi/i),opt*sin(pi/i));
        for(j=0;j<n;j+=i<<1)
            for(w=com(1,0),k=0;k<i;k++,w=w*wn)
            {
                x=a[k+j], y=a[k+j+i]*w;
                a[k+j]=x+y, a[k+j+i]=x-y;
            }
    }
    if(opt==-1)for(i=0;i<n;i++)a[i].x/=n;
}
inline void juan(com *a, com *b, com *c)
{
    fft(a,up,1), fft(b,up,1);
    for(int i=0;i<up;i++)c[i]=a[i]*b[i];
    fft(c,up,-1);
}
void init()
{
    int i, L, d, sa=0, sb=0, t;
    scanf("%d%d",&N,&M);
    for(i=0;i<N;i++)scanf("%lf",&a[i].x),a[N+i].x=a[i].x;
    for(i=0;i<N;i++)scanf("%lf",&b[i].x),b[N+i].x=b[i].x;
    for(i=0;i<2*N-1-i;i++)swap(a[i],a[2*N-1-i]);
    for(up=1,L=0;up<4*N;up<<=1)L++;
    for(i=0;i<up;i++)R[i]=(R[i>>1]>>1)|((i&1)<<(L-1));
    for(i=0;i<N;i++)ans+=a[i].x*a[i].x+b[i].x*b[i].x, sa+=a[i].x, sb+=b[i].x;
    for(d=0,t=0x7fffffff;d<=M;d++)t=min(t,d*d*N+2*d*(sa-sb));
    ans+=t;
}
int main()
{
    int i; double x;
    init();
    juan(a,b,c);
    for(x=-1e100,i=N-1;i<=2*N-2;i++)x=max(x,c[i].x-c[i-N].x);
    ans-=int(x+0.5)*2;
    printf("%d",ans);
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值