您的位置:首页 > 其它

BZOJ 4827 [Hnoi2017]礼物

2017-05-01 16:04 435 查看
FFT

把式子展开完发现c和顺序无关,可以直接算,最小化这个式子就是最小化一个乘积的东西,也就是一个裸的FFT……

涨姿势,C++有一个四舍五入的函数叫round()

#include<cmath>
#include<cstdio>
#include<algorithm>
#define N 400005
using namespace std;
namespace runzhe2000
{
typedef long long ll;
typedef double db;
int n, m, len; ll c;
db sum_a, sum_b;
ll sum_a2, sum_b2;
struct comp
{
db r, i;
comp operator + (const comp &that) const {return (comp){r+that.r, i+that.i};}
comp operator - (const comp &that) const {return (comp){r-that.r, i-that.i};}
comp operator * (const comp &that) const {return (comp){r*that.r-i*that.i, r*that.i+i*that.r};}
}w
, a
, b
;
void init()
{
db pi = acos(-1.0);
for(int i = 0; i < len; i++)
w[i] = (comp){cos(2*pi*i/len), sin(2*pi*i/len)};
}
void FFT(comp *a, int n, comp *w)
{
for(int i = 0, j = 0; i < n; i++)
{
if(i<j) swap(a[i], a[j]);
for(int l = n>>1; (j^=l)<l; l>>=1);
}
for(int i = 2; i <= n; i <<= 1)
{
int m = i>>1;
for(int j = 0; j < n; j += i)
{
for(int k = 0; k < m; k++)
{
comp tmp = w[n/i*k] * a[j+k+m];
a[j+k+m] = a[j+k] - tmp;
a[j+k] = a[j+k] + tmp;
}
}
}
}
void main()
{
scanf("%d%d",&n,&m);
for(int i = 1; i <= n; i++)
{
scanf("%lf",&a[i+n-1].r);
sum_a += a[i+n-1].r;
sum_a2 += a[i+n-1].r*a[i+n-1].r;
}
for(int i = 1; i <= n; i++)
{
scanf("%lf",&b[n-i].r);
sum_b += b[n-i].r;
b[n-i+n].r = b[n-i].r;
sum_b2 += b[n-i].r*b[n-i].r;
}
c = (ll)round((db)(sum_b-sum_a)/n);
for(len = 1; len <= (n<<2); len <<= 1);

for(int i = 0; i < len; i++) a[i].i = b[i].i = 0;
init(); FFT(a,len,w); FFT(b,len,w);
for(int i = 0; i < len; i++) a[i] = a[i] * b[i];
reverse(a+1, a+len); FFT(a, len,w);
for(int i = 0; i < len; i++) a[i].r /= len;

ll mx = 0;
for(int i = 2*n-1, ii = 3*n-2; i <= ii; i++) mx = max(mx, (ll)(0.5 + a[i].r));
printf("%lld\n",n*c*c+(ll)(sum_a-sum_b)*2*c+sum_a2+sum_b2-2*mx);
}
}
int main()
{
runzhe2000::main();
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: