题目地址

洛谷P3338

Solution

第一道FFT的应用AC祭!

我们要求:

\[E_j=\frac{F_j}{q_j}=\sum_{i<j}\frac{q_i}{(i-j)^2}-\sum_{i>j}\frac{q_i}{(i-j)^2}
\]

(\(q_j\) 直接在除法的时候消掉了qwq)

  • Step 0 卷积是什么?

首先我们要有明确的目标,我们要把上面的式子推成卷积的形式,我们就要来回顾一下卷积是什么。卷积的形式如下:

\[C_k=\sum_{i=0}^{k}A_i*B_{k-i}
\]

  • Step 1 直接推式子

有了目标,我们就好来推式子了(推式子真好玩),下面给出推理的重要步骤,尽量没有繁琐的步骤,读者可以自己思考一下。

\[E_j=\sum_{i<j}\frac{q_i}{(i-j)^2}-\sum_{i>j}\frac{q_i}{(i-j)^2}
\]

改变一下 \(\sum\) 的上下标表示形式,原式变成

\[\sum_{i=1}^{j-1}\frac{q_i}{(i-j)^2}-\sum_{i=j+1}^{n}\frac{q_i}{(i-j)^2}
\]

如果 \(i=j\) 也累加进去,对答案不影响,所以式子变成

\[\sum_{i=1}^{j}\frac{q_i}{(i-j)^2}-\sum_{i=j}^{n}\frac{q_i}{(i-j)^2}
\]

  • Step 2 转化

设 \(f[i]=q_i,g[i]=\frac{1}{i^2}\) ,所以原式变成

\[\sum_{i=1}^{j}f[i]*g[j-i]-\sum_{i=j}^{n}f[i]*g[i-j]
\]

令 \(f[0]=0,g[0]=0\),则原式变成

\[\sum_{i=0}^{j}f[i]*g[j-i]-\sum_{i=j}^{n}f[i]*g[i-j]
\]

这时我们发现,左边已经是一个卷积的形式,所以我们直接来推右边

将 \(\sum_{i=j}^{n}f[i]*g[i-j]\) 展开,发现:

\[f[j]*g[0]+f[j+1]*g[1]+...+f[j+(n-j)]*g[n-j]
\]

所以我们可以将原式写成

\[\sum_{i=0}^{n-j}f[j+i]*g[i]
\]

  • Step 3 继续转化

引入 \(f'[i]=f[n-i]\) ,实际上这是一种翻转的套路。则原式可写为

\[\sum_{i=0}^{n-j}f'[n-(j+i)]*g[i]
\]

\[\sum_{i=0}^{n-j}f'[n-j-i]*g[i]
\]

令 \(t = n-j\),则原式等于

\[\sum_{i=0}^{t}f'[t-i]*g[i]
\]

至此,我们成功的把两个式子化成了卷积!!!

总结一下:

\[E_j=\sum_{i=0}^{j}f[i]*g[j-i]-\sum_{i=0}^{t}f'[t-i)]*g[i]
\]

- Step 4 \(FFT\)加速卷积

设有多项式 \(A(x)=\sum_{i=0}^{n}f[i]\) , \(B(x)=\sum_{i=0}^{n}g[i]\) , \(C(x)=\sum_{i=0}^{n}f'[i]\),

我们令 \(L(x)=A(x)*B(x)\) , \(R(x)=C(x)*B(x)\)

所以 \(Ans[i]=l_i - r_{n-i}\) (\(l_i,r_i\) 分别是多项式 \(L(x)\) 和 \(R(x)\) \(x^i\) 的系数)

- Step 5 读到这里,你和暴力选手还没有差别 (逃

世界上卡你精度的办法有千千万万种。 ----By me

注意 \(g[i]=\frac{1}{i^2}\)

楼主在处理这里的时候写的是 1.0/(i*i*1.0),交上去只有 \(30pts\)。

在题解中看到大佬们处理这里时用的 (double)(1.0 / i / i),改一下后,\(100pts\)。

如果大家对处理精度问题有什么独特的见解,记得和我分享分享QwQ

Code

Talk is cheap.Show me the code.

#include<bits/stdc++.h>
using namespace std;
inline int read() {
int x=0,f=1; char ch=getchar();
while(ch<'0' || ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
while(ch>='0'&&ch<='9') { x=(x<<3)+(x<<1)+(ch^48); ch=getchar(); }
return x * f;
}
const int N = 400007;
const double pi = acos(-1.0);
int n;
int rev[N];
struct CP {
double x,y;
CP operator + (CP el) { return (CP)<%x+el.x , y+el.y%>; }
CP operator - (CP el) { return (CP)<%x-el.x , y-el.y%>; }
CP operator * (CP el) { return (CP)<%x*el.x-y*el.y , x*el.y+y*el.x%>; }
}a[N],b[N],c[N];
void FFT(CP *A,int n,int flag) {
for(int i=0;i<n;++i) if(i < rev[i]) swap(A[i],A[rev[i]]);
for(int mid=1;mid<n;mid<<=1) {
CP Wn = (CP)<%cos(2*pi/(mid<<1)) , flag*sin(2*pi/(mid<<1))%>;
for(int i=0;i<n;i+=(mid<<1)) {
CP W = (CP)<%1 , 0%>;
for(int j=0;j<mid;++j,W=(W*Wn)) {
CP tmp0 = A[i+j], tmp1 = W*A[i+mid+j];
A[i+j] = tmp0 + tmp1;
A[i+mid+j] = tmp0 - tmp1;
}
}
}
if(flag == -1) {
for(int i=0;i<n;++i) A[i].x /= n;
}
}
int main()
{
//freopen("Li.txt","r",stdin);
//freopen("My.out","w",stdout);
n = read();
for(int i=1;i<=n;++i) {
scanf("%lf",&a[i].x);
c[n-i].x = a[i].x;
b[i].x = (double)(1.0 / i / i);
}
int lim = 1, L = 0; while(lim <= (n<<1)) lim <<= 1, ++L;
for(int i=0;i<lim;++i) rev[i] = (rev[i>>1]>>1) | ((i&1)<<(L-1));
FFT(a,lim,1), FFT(b,lim,1), FFT(c,lim,1);
for(int i=0;i<lim;++i) a[i] = a[i]*b[i], c[i] = c[i]*b[i];
FFT(a,lim,-1), FFT(c,lim,-1);
for(int i=1;i<=n;++i)
printf("%.3lf\n",a[i].x-c[n-i].x);
return 0;
}
/*
5
4006373.885184
15375036.435759
1717456.469144
8514941.004912
1410681.345880 -16838672.693
3439.793
7509018.566
4595686.886
10903040.872
*/

Summary

推理过程大部分是我自己的手推,和其他大佬不同请见谅,毕竟条条大路通罗马呗。

过程中的转折点就是我推不动的时候,所这个题目让我学会了:

  • 卷积 (雾 ,要把式子推成卷积形式

  • 巧设数组代替抽象的数学式子

  • 翻转序列的技巧

我多项式还是太菜了呢,赶紧去做题吧!QAQ

[ZJOI2014]力 题解的更多相关文章

  1. BZOJ3527:[ZJOI2014]力——题解

    http://www.lydsy.com/JudgeOnline/problem.php?id=3527 给出n个数qi,给出Fj的定义如下: 令Ei=Fi/qi,求Ei. 参考:https://ww ...

  2. [ZJOI3527][Zjoi2014]力

    [ZJOI3527][Zjoi2014]力 试题描述 给出n个数qi,给出Fj的定义如下: 令Ei=Fi/qi.试求Ei. 输入 包含一个整数n,接下来n行每行输入一个数,第i行表示qi. 输出 有n ...

  3. [洛谷P3338] [ZJOI2014]力

    洛谷题目链接:P3338 [ZJOI2014]力 题目描述 给出n个数qi,给出Fj的定义如下: \[F_j = \sum_{i<j}\frac{q_i q_j}{(i-j)^2 }-\sum_ ...

  4. bzoj3527: [Zjoi2014]力 fft

    bzoj3527: [Zjoi2014]力 fft 链接 bzoj 思路 但是我们求得是 \(\sum\limits _{i<j} \frac{q_i}{(i-j)^2}-\sum_{i> ...

  5. 洛谷 P3338 [ZJOI2014]力 解题报告

    P3338 [ZJOI2014]力 题目描述 给出n个数qi,给出Fj的定义如下: \(F_j = \sum_{i<j}\frac{q_i q_j}{(i-j)^2 }-\sum_{i>j ...

  6. 【BZOJ 3527】 3527: [Zjoi2014]力 (FFT)

    3527: [Zjoi2014]力 Time Limit: 30 Sec  Memory Limit: 256 MBSec  Special JudgeSubmit: 2003  Solved: 11 ...

  7. P3338 [ZJOI2014]力(FFT)

    题目 P3338 [ZJOI2014]力 做法 普通卷积形式为:\(c_k=\sum\limits_{i=1}^ka_ib_{k-i}\) 其实一般我们都是用\(i=0\)开始的,但这题比较特殊,忽略 ...

  8. [Luogu P3338] [ZJOI2014]力 (数论 FFT 卷积)

    题面 传送门: 洛咕 BZOJ Solution 写到脑壳疼,我好菜啊 我们来颓柿子吧 \(F_j=\sum_{i<j}\frac{q_i*q_j}{(i-j)^2}-\sum_{i>j} ...

  9. 笔记-[ZJOI2014]力

    [ZJOI2014]力 \[\begin{split} E_j=&\sum_{i=1}^{j-1}\frac{q_i}{(i-j)^2}-\sum_{i=j+1}^{n}\frac{q_i}{ ...

随机推荐

  1. Maven POM 模板[z]

    https://juejin.im/post/5cc826a5f265da03a33c443a [z]https://juejin.im/post/5cc826a5f265da03a33c443a S ...

  2. python之拷贝文件

    做了个小实验, 用于拷贝文件夹下面的jpg. 用于拓展, 可以引入类和方法, 拷贝你指定的任意类型的文件. import os src = 'C:\\Users\\Administrator\\Des ...

  3. EasyPHP(php集成环境)下载 v5.4.6官方安装版

    EasyPHP版本:12.1(32位) PHP版本:5.4.6 MYSQL版本:5.5.27 APACHE版本:2.4.2 下载地址请点击

  4. 设置terminal 命令别名

    vi -/.bash_profile code () { VSCODE_CWD="$PWD" open -n -b "com.microsoft.VSCode" ...

  5. JavaScript中二进制与10进制互相转换

    webpack打包生成的代码中涉及了一些二进制位与的操作, 所以今天来学习一下JavaScript中的二进制与十进制转换操作吧 十进制转二进制: var num = 100 num.toString( ...

  6. Linux下监控网卡流量的软件Nload

    Linux下监控网卡流量的软件Nload 安装nload: # wget http://www.roland-riegel.de/nload/nload-0.7.2.tar.gz # tar zxvf ...

  7. CSS3实用指南 初读笔记

    1.7.1  浏览器前缀 当一个浏览器实现了一个新的属性.值或者选择器,而这个特性还不是处于候选推荐标准状态的时候,在属性前面会添加一个前缀以便于它的渲染引擎识别. CSS属性的浏览器前缀:    前 ...

  8. ABAP的smartform赋值

    添加文本后, 在输出选项中指定行/列

  9. ETH 全节点的远程Debug环境搭建

    ETH全节点还是很浪费资源的,尤其是在同步下来所有区块链,如果你打算在本地进行全节点的Debug吗,有点不现实.这个文档 编译,在要运行的机器上面安装devel,一般的方法是,编译好之后,放到服务器上 ...

  10. Unity中的动画系统和Timeline(3) 混合树和动画匹配

    混合树 前面我们通过在Animation界面添加单独的动作来控制动画,这样做比较麻烦,每个单独的属性,比如站立,奔跑等,都需要单独的代码来控制.现在我们可以通过使用混合树,其基本思想是将相近的动画混合 ...