题目:

BZOJ3527

分析:

FFT应用第一题……

首先很明显能把\(F_j\)约掉,变成:

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

然后去膜拜题解,我们知道两个多项式相乘的方式如下:

\[C_j=\sum_{i=0}^j A_iB_{j-i}
\]

那么,如果把\(E_j\)的表达式化成上面那个形式,就可以用FFT计算了。(不会FFT?戳我:【知识总结】快速傅里叶变换(FFT)

先看减号前面的部分。显然可以变成(为了叙述方便,读入的\(q\)的下标为\([0,n)\)):

\[C_j=\sum_{i=0}^j F_iG_{j-i}
\]

其中\(F_i=q_i\),\(G_i=\frac{1}{i^2}\)。特别地,\(G_0=0\)。

减号后面要处理\(j\)位置以后的,怎么办?大力把\(q\)数组翻过来,这样就相当于求\(n-j-1\)以前的了:

\[D_j=\sum_{i=0}^{j} F'_iG_{j-i}
\]

其中\(F'_j=q_{n-j-1}\)

那么答案\(E_j=C_j-D_{n-j-1}\)

代码:

注意\(g\)要初始化……

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cctype>
#include <cmath>
using namespace std;
#define _ 0 namespace zyt
{
template<typename T>
inline void read(T &x)
{
char c;
bool f = false;
x = 0;
do
c = getchar();
while (c != '-' && !isdigit(c));
if (c == '-')
f = true, c = getchar();
do
x = x * 10 + c - '0', c = getchar();
while (isdigit(c));
if (f)
x = -x;
}
inline void read(double &x)
{
scanf("%lf", &x);
}
template<typename T>
inline void write(T x)
{
static char buf[20];
char *pos = buf;
if (x < 0)
putchar('-'), x = -x;
do
*pos++ = x % 10 + '0';
while (x /= 10);
while (pos > buf)
putchar(*--pos);
}
inline void write(const double a, const int fix = 9)
{
printf("%.*f", fix, a);
}
const int B = 17, N = 1 << (B + 1) | 10;
const double PI = 3.141592653589793238462643383279502884197169399375105820974944L;
namespace FFT
{
int rev[N];
struct cpx
{
double x, y;
cpx(const double _x = 0.0, const double _y = 0.0)
: x(_x), y(_y) {}
cpx operator + (const cpx &b) const
{
return cpx(x + b.x, y + b.y);
}
cpx operator - (const cpx &b) const
{
return cpx(x - b.x, y - b.y);
}
cpx operator * (const cpx &b) const
{
return cpx(x * b.x - y * b.y, x * b.y + y * b.x);
}
cpx conj() const
{
return cpx(x, -y);
}
}omega[N], inv[N];
void init(const int lg2)
{
for (int i = 0; i < (1 << lg2); i++)
{
rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (lg2 - 1));
omega[i] = cpx(cos(2 * PI * i / (1 << lg2)), sin(2 * PI * i / (1 << lg2)));
inv[i] = omega[i].conj();
}
}
void fft(cpx *a, const int n, const cpx *w)
{
for (int i = 0; i < n; i++)
if (i < rev[i])
swap(a[i], a[rev[i]]);
for (int len = 1; len < n; len <<= 1)
for (int i = 0; i < n; i += (len << 1))
for (int k = 0; k < len; k++)
{
cpx tmp = a[i + k] - w[k * (n / (len << 1))] * a[i + len + k];
a[i + k] = a[i + k] + w[k * (n / (len << 1))] * a[i + len + k];
a[i + len + k] = tmp;
}
}
void solve(cpx *a, cpx *b, const int n)
{
fft(a, n, omega), fft(b, n, omega);
for (int i = 0; i < n; i++)
a[i] = a[i] * b[i];
fft(a, n, inv);
for (int i = 0; i < n; i++)
a[i].x /= n;
}
}
using namespace FFT;
int n;
double q[N];
cpx f[N], g[N], revf[N];
int work()
{
read(n);
for (int i = 0; i < n; i++)
{
read(q[i]);
f[i] = revf[n - i - 1] = q[i];
}
int m = n << 1, lg2 = 0;
for (n = 1; n < m; n <<= 1)
++lg2;
init(lg2);
for (int i = 0; i < (m >> 1); i++)
g[i] = (i ? 1.0 / ((double)i * i) : 0.0);
solve(f, g, n);
for (int i = 0; i < (m >> 1); i++)
g[i] = (i ? 1.0 / ((double)i * i) : 0.0);
for (int i = (m >> 1); i < n; i++)
g[i] = 0;
solve(revf, g, n);
for (int i = 0; i < (m >> 1); i++)
write(f[i].x - revf[(m >> 1) - i - 1].x), putchar('\n');
return ~~(0^_^0);
}
} int main()
{
return zyt::work();
}

最新文章

  1. sql server报:名称 不是有效的标识符
  2. 记录visual Studio使用过程中的两个问题
  3. Asp.Net MVC+BootStrap+EF6.0实现简单的用户角色权限管理8
  4. ::after::before清除浮动原理
  5. ActiveMQ的几种消息持久化机制
  6. java Jsoup 抓取页面数据
  7. Sed 直接修改文件
  8. c语言const
  9. unix c 02
  10. ffmpeg+SDl+ 播放器 -01
  11. install tool
  12. 在toolbar里动态创建多个button(ext.net)
  13. 关于数据库中datareader的用法
  14. docker:(1)docker基本命令使用及发布镜像
  15. 推荐一些用CRF做图像语义分割的资源
  16. vmware不能装ghost系统怎么解决
  17. OC Swift中检查代码行数
  18. urllib3
  19. MSCRM 2011中过滤化查询的实现方法和禁用选择视图
  20. tomcat与jboss等容器的区别

热门文章

  1. DAS、NAS、SAN、iSCSI 存储方案概述
  2. HDU 4780 Candy Factory
  3. 数论结论 nefu 702
  4. 转载 - C - 枚举类型详解
  5. qscoj Round 1(div 2)
  6. [bzoj1084][SCOI2005]最大子矩阵(DP)
  7. 非常适合新手的jq/zepto源码分析05
  8. 解决canvas跨域问题(图片,视频资源跨域)
  9. 用JQuery实现选中select里面的option显示对应的div
  10. PHP array_merge_recursive()