Luogu P3338 [ZJOI2014]力
P3338 [ZJOI2014]力
题目大意
给出 个数 ,定义
对 ,求 的值。
分析
我们来复现一下推导过程,熟悉一下。
我们考虑转化,设,所以原式变为
令f[0]=0,g[0]=0
,考虑一下为什么这么定义?因为我们想让i=j
的项无意义,这点对很多推导中的式子定义都有意义。
则我们可以改写式子
此时可以发现左边已经变为卷积形式了,考虑将右边转化为卷积形式,我们将右边展开
因此右边可以改写为
接下来,我们用到一个技巧,翻转。我们引入f'[i]=f[n-i]
,由此式子可以写为。
即
令t=n-j
,则式子的最终形式为
最后总结一下,式子即为
最后,我们分别求左边与右边的卷积,最后答案即为
Ac_code
#include<bits/stdc++.h>
#define ios ios::sync_with_stdio(false); cin.tie(0), cout.tie(0)
using namespace std;
const int N = 3e5 + 10;
const double PI = acos(-1);
struct Complex
{
double x,y;
Complex(double x = 0,double y = 0) : x(x), y(y) {}
};
//复数乘法:模长相乘,幅度相加
Complex operator * (Complex J, Complex Q) {return Complex(J.x * Q.x - J.y * Q.y, J.x * Q.y + J.y * Q.x);}
Complex operator - (Complex J, Complex Q) {return Complex(J.x - Q.x, J.y - Q.y);}
Complex operator + (Complex J, Complex Q) {return Complex(J.x + Q.x, J.y + Q.y);}
namespace FFT
{
typedef vector<Complex> poly;
int R[N];//二进制翻转 二进制位数 补齐的2的整数幂N
int FFT_init(int n)
{
int L = 0,limit = 1;
while(limit<=n) limit <<= 1,L ++ ;
// 补成2的整次幂,也就是N
for(int i = 0; i < limit; ++ i)
R[i] = (R[i >> 1] >> 1) | ((i & 1) << (L - 1));
return limit;
}
void FFT(poly &A, int type,int limit)
{
A.resize(limit);
for(int i = 0; i < limit; ++ i)
if(i < R[i])
swap(A[i], A[R[i]]);
//i小于R[i]时才交换,防止同一个元素交换两次,回到它原来的位置。
//从底层往上合并
for(int mid = 1; mid < limit; mid <<= 1) {
//待合并区间长度的一半,最开始是两个长度为1的序列合并,mid = 1;
Complex wn(cos(PI / mid), type * sin(PI / mid));//单位根w_n^1;
for(int len = mid << 1, pos = 0; pos < limit; pos += len) {
//len是区间的长度,pos是当前的位置,也就是合并到了哪一位
Complex w(1, 0);//幂,一直乘,得到平方,三次方...
for(int k = 0; k < mid; ++ k, w = w * wn) {
//只扫左半部分,蝴蝶变换得到右半部分的答案,w 为 w_n^k
Complex x = A[pos + k];//左半部分
Complex y = w * A[pos + mid + k];//右半部分
A[pos + k] = x + y;//左边加
A[pos + mid + k] = x - y;//右边减
}
}
}
if(type == 1) return ;
for(int i = 0; i < limit; ++ i)
A[i].x /= limit;
//最后要除以limit也就是补成了2的整数幂的那个N,将点值转换为系数
//(前面推过了点值与系数之间相除是N)
}
poly poly_mul(poly A,poly B)
{
int deg = A.size() + B.size() - 1;
int limit = FFT_init(deg);
poly C(limit);
FFT(A,1,limit),FFT(B,1,limit);
for(int i=0;i<limit;++i) C[i] = A[i]*B[i];
// cout<<cnt<<endl;
FFT(C,-1,limit);
C.resize(deg);
return C;
}
};
using FFT::poly;
using FFT::poly_mul;
int main()
{
int n;scanf("%d",&n);
poly a(n+1),b(n+1),c(n+1);
for(int i=1;i<=n;i++)
{
scanf("%lf",&a[i].x);
c[n-i].x = a[i].x;
b[i].x = 1.0/i/i;
}
a = poly_mul(a,b,1);
c = poly_mul(b,c,2);
for(int i=1;i<=n;i++) printf("%.3lf\n",a[i].x-c[n-i].x);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步