羅区P3338] [ZJOI2014力 / BZOJ 3527電力問題解決
問題の意味
正の整数で指定された\(N-(1 \ n型のLeq \のLeq 10 ^ 5)\) 、ならびに\(N- \)浮動小数点配列要素\(Q(0 <Q_I <10 ^ 9)\) 。すべてのために必要な\(I \で[1、N-] \)、出力
\ [E_j = \ sum_ {I = 1} ^ {J-1} \ FRAC {Q_I \回q_j} {(IJ)^ 2} - \ sum_ {I = J +
1} ^ N \ FRAC] {(IJ)^ 2} \ {Q_I \回q_j} 注:出力を超えないことにより、標準回答に応答したとき(10 ^ \ { - 2} \) 、それが正解とみなされています。
問題の解決策
明らかに、暴力が不可能であるので、検討(FFT \)\コンボリューション処理することができる。
まず、満たすべき畳み込み配列可能な条件を考慮して:
\ [C_I = \ sum_ {J} = 0 ^ ia_j \タイムズB_ {NJは} \]
私たちは少し畳み込みするオリジナルスタイルの外観の良いを取る必要がありますので。
我々は、同様になるかもしれない(a_iを= Q_I、b_i = \ FRAC {1} {I ^ 2} \)\、あなたは元に入力することができますいくつかの変形行う:
\ [E_j = \ sum_ {I = 1} ^ {J-1} \ FRAC {Q_I \タイムズQ_j} {(のIJ)^ 2} - \ sum_ {IがJ +を= 1} ^ N- \ FRAC {({Q_I \回q_j} IJ)^ 2} = \ sum_ {i = 1} ^ {J-1} a_ib_ {JI} - \ sum_ {iが= J + 1} ^ {n}はa_ib_ {IJ} \ ]
我々はせたとき(A_0 = B_0 = 0 \ \ ) 、変形を見つけることは困難ではない
\ [\ sum_ {I = 0 \ sum_ {iが= J} ^ { - } ^ {J} a_ib_ {JI} N- \]のa_ib_} {} IJ
この時点で..正しい畳み込みクレームが満たされている遺骨の前に、我々は、単一の対処
右側に変形することを証明することは難しいことではありません:
\ [\ sum_ {私はJを= } ^ {n}はa_ib_ {IJ
} = \ sum_ {i = 0} ^ {NJ} A_ {I + J} b_i \] 次に、逆思考の使用、そう\(A_ C_I = {ニッケル} \) 、それはに変換することができます
\ [\ Sum_ {I = 0
} ^ {NJ} A_ {I + J} b_i = \ sum_ ^ {NJ} C_ {NIJ} b_i \ {iが0 =}]をこのように、第2の式も満足していますコンボリューション条件はそれ!
私たち\(\)と\(B \)を実行するには、\(FFT \)をした後、\(B \)と\(C \)を実行するために\(FFT \)を設定し、以下のようにして得られた二つの配列(P \)\と\(Q \) 、次に答えが\(E_j = Q_-p_j NJ} {\)、PUT \(FFT \)ボードはできます。
コード
#include<bits/stdc++.h>
using namespace std;
#define M_PI 3.141592653589793
typedef complex<long double> comp;
const int MAXN=100010;
const comp I(0,1);
int n;
comp a[MAXN*4];
comp b[MAXN*4];
inline void change(comp *f,int len)
{
for(int i=1,j=len>>1;i<len-1;i++)
{
if(i<j) swap(f[i],f[j]);
int k=len>>1;
while(j>=k)
{
j-=k;
k>>=1;
}
if(j<k) j+=k;
}
}
inline void FFT(comp *f,int len,int rev)
{
change(f,len);
for(int h=2;h<=len;h<<=1)
{
comp wn=exp(I*(long double)(2*M_PI/h*rev));
for(int i=0;i<len;i+=h)
{
comp cur(1,0);
for(int j=i;j<i+(h>>1);j++)
{
comp p=f[j],q=cur*f[j+(h>>1)];
f[j]=p+q,f[j+(h>>1)]=p-q;
cur*=wn;
}
}
}
if(rev==-1)
for(int i=0;i<len;i++) f[i]/=len;
}
comp c[MAXN*4];
int len;
int main()
{
scanf("%d",&n);
for(int i=0;i<n;i++)
{
long double x;
scanf("%Lf",&x);
a[i]={x,0};
}
for(int i=1;i<n;i++) b[i]=1.0/(1.0*(long double)i*(long double)i);
for(int i=0;i<n;i++) c[i]=a[n-i];
len=1;
while(len<=2*n) len<<=1;
FFT(a,len,1),FFT(b,len,1),FFT(c,len,1);
for(int i=0;i<len;i++) c[i]*=b[i],b[i]*=a[i];
FFT(b,len,-1),FFT(c,len,-1);
for(int i=0;i<n;i++) printf("%.3Lf\n",real(b[i]-c[n-i]));
return 0;
}
追伸
私は初めて(FFT \)\演習は、私は(静かに2の問題解決のアイデアへの解決策をお読みに加えて)かなりよくπが実際に精度の欠如赤の結果である前に、もっと惨めに感じ、すべてのポイントは、数十の違いです幸いなことに、道の後QAQは最後に、私は、Tucao 1に数学の問題を持っている......バーの上に、それの背面側に切り替わる(LaTeXの\)\それを得るためになりましたので......書くことは本当に難しいQAQ