P3338 [ZJOI2014]力

\(\color{#0066ff}{ 题目描述 }\)

给出n个数qi,给出Fj的定义如下:

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

令Ei=Fi/qi,求Ei.

\(\color{#0066ff}{输入格式}\)

第一行一个整数n。

接下来n行每行输入一个数,第i行表示qi。

接下来为边

\(\color{#0066ff}{输出格式}\)

n行,第i行输出Ei。

与标准答案误差不超过1e-2即可。

\(\color{#0066ff}{输入样例}\)

5
4006373.885184
15375036.435759
1717456.469144
8514941.004912
1410681.345880

\(\color{#0066ff}{输出样例}\)

-16838672.693
3439.793
7509018.566
4595686.886
10903040.872

\(\color{#0066ff}{数据范围与提示}\)

对于30%的数据,n≤1000。

对于50%的数据,n≤60000。

对于100%的数据,n≤100000,0<qi<1000000000。

\(\color{#0066ff}{ 题解 }\)

\(q_i\)除掉

\(f_i=p_i, g_i=\frac{1}{i^2}\)

\(\begin{aligned}F_i=\sum_{j = 1}^{i - 1}f(j)*g(i-j)-\sum_{j = i +1}^{n}f(j)*g(j-i)\end{aligned}\)

考虑一个卷积\(\begin{aligned}f_n=\sum_{i = 1}^n g(i)*h(n - i) \end{aligned}\)

一个函数\(f(i)\),当做多项式,就是\(x^i\)的系数

不难发现,因为(i + n - i) = n

所以上面的卷积其实就是g和h卷起来第n项的系数!

回到本题

将前面的\(\sum\)用FFT算出来,因为\(j+i-j=i\),因此前面的部分第i项的系数就是第i个ans

后面的\(\sum\)不好弄,要把j消掉,可以将后面翻转成\(\begin{aligned}\sum_{j = i + 1}^{n}f(j)*g(n - (j - i)+1)\end{aligned}\)

\(j + n -j+i+1=n+i+1\),所以后半部分的第i个ans就是卷积的第n+i+1项(把g翻转后再卷积)

#include<bits/stdc++.h>
#define LL long long
LL in() {
	char ch; LL x = 0, f = 1;
	while(!isdigit(ch = getchar()))(ch == '-') && (f = -f);
	for(x = ch ^ 48; isdigit(ch = getchar()); x = (x << 1) + (x << 3) + (ch ^ 48));
	return x * f;
}
const double pi = acos(-1);
const int maxn = 3e5 + 10;
double p[maxn];
struct node {
	double x, y;
	node(double x = 0, double y = 0): x(x), y(y) {}
	friend node operator + (const node &a, const node &b) { return node(a.x + b.x, a.y + b.y); }
	friend node operator - (const node &a, const node &b) { return node(a.x - b.x, a.y - b.y); }
	friend node operator * (const node &a, const node &b) { return node(a.x * b.x - a.y * b.y, a.x * b.y + a.y * b.x); }
	friend node operator / (const node &a, const double &b) { return node(a.x / b, a.y / b); }
}A[maxn], B[maxn], E[maxn], F[maxn];
int len, n, r[maxn];
void FFT(node *D, int flag) {
	for(int i = 0; i < len; i++) if(i < r[i]) std::swap(D[i], D[r[i]]);
	for(int l = 1; l < len; l <<= 1) {
		node w0(cos(pi / l), flag * sin(pi / l));
		for(int i = 0; i < len; i += (l << 1)) {
			node w(1, 0), *a0 = D + i, *a1 = D + i + l;
			for(int k = 0; k < l; k++, a0++, a1++, w = w * w0) {
				node tmp = *a1 * w;
				*a1 = *a0 - tmp;
				*a0 = *a0 + tmp;
			}
		}
	}
	if(flag == -1) for(int i = 0; i < len; i++) D[i] = D[i] / len;
}
int main() {
	n = in();
	for(int i = 1; i <= n; i++) scanf("%lf", &p[i]);
	for(int i = 1; i <= n; i++) A[i].x = p[i];
	for(int i = 1; i <= n; i++) B[i].x = 1.0 / i / i;
	for(len = 1; len <= n + n + 2; len <<= 1);
	for(int i = 0; i < len; i++) r[i] = (r[i >> 1] >> 1) | ((i & 1) * (len >> 1));
	FFT(A, 1), FFT(B, 1);
	for(int i = 0; i < len; i++) E[i] = A[i] * B[i];
	FFT(E, -1);
	for(int i = 0; i < len; i++) A[i] = B[i] = node();
	for(int i = 1; i <= n; i++) A[i].x = p[i];
	for(int i = 1; i <= n; i++) B[i].x = 1.0 / (n - i + 1) / (n - i + 1); 
	FFT(A, 1), FFT(B, 1);
	for(int i = 0; i < len; i++) F[i] = A[i] * B[i];
	FFT(F, -1);
	for(int i = 1; i <= n; i++) printf("%.3f\n", E[i].x - F[n + i + 1].x);
	return 0;
}
posted @ 2019-01-15 09:06  olinr  阅读(158)  评论(0编辑  收藏  举报