从今天开始,蒟蒻_WA自动机也要学多项式辣!虽然我什么都不会,但是好在我们机房有HA A队队长LCHCTP_998244353巨佬啊!所以天天被巨佬爆踩
lg P3723 [AH/HNOI2017]礼物
题目大意
两个长度为n的环形整数数列,您可以进行两种操作: 1. 对一个数列的所有数加上一个值C 2. 将一个数列旋转一位
定义两个数列的差异值为
\[\sum_{i=1}^{n}(x_i-y_i)^2\] 求差异值的最小值。
数据范围
30%的数据满足\(n≤500,m≤10\);
70%的数据满足\(n≤5000\);
100%的数据满足\(1≤n≤50000, 1≤m≤100, 1≤a_i≤m\)。 ## 题解: 考虑如何使上式值最小
设给x序列加了一个数\(C\in \mathbb{Z}\),则答案为\((x_i-y_i+C)^2\)
拆掉上面的柿子..
\[(x_i-y_i+C)^2=x_i^2+y_i^2+C^2-2x_iy_i+2C(x_i-y_i)\] 柿子中除了\(-2x_iy_i\)都是定值,所以我们只需要最大化\(x_iy_i\) 这个非常像一个卷积..再看看数据范围,也是FFT的数据范围。。
对于这样的柿子我们通常的处理方法就是把一个序列翻转。这样就变成了卷积,可以\(O(n \log n)\)算出值了。现在我们要最大化所有可能的这样的值,所以考虑断环为链,把A复制一遍接在末尾。算出来的\(a[n+1..n+n]\)就是所有可能的答案。 再考虑关于C的项,含有C的项总和为 \[nC^2-2C\sum_{i=1}^{n}x_iy_i\] 这是关于C的二次函数,用对称轴就好了。注意C是整数,所以算出对称轴后要四舍五入取接近的整数。 注意数学函数调用时一定要加std::,不然会出现奇怪的精度问题。。
我的代码(NTT实现
1 |
|
lg P3338 [ZJOI2014]力
题目大意:
给出\(n\)个数\(q_i\),给出\(F_j\)的定义如下:
\(F_j = \sum_{i<j}\frac{q_i q_j}{(i-j)^2 }-\sum_{i>j}\frac{q_i q_j}{(i-j)^2 }\)
令\(E_i=F_i/q_i\),求\(E_i\).
数据范围:
对于\(30\%\)的数据,\(n≤1000\)。 对于\(50\%\)的数据,\(n≤60000\)。 对于\(100\%\)的数据,\(n≤100000\),\(0<q_i<1000000000\)。
题解:
首先,可以直接得到\(E_i\)的表达式: \[E_i=\sum_{j<i}\frac{q_j}{(i-j)^2}-\sum_{j>i}\frac{q_j}{(i-j)^2}\] 分开考虑每一项: 两项的推导方式差不多,所以只用后面的那一项做栗子吧: 我们观察到这很像一个卷积的形式,所以我们考虑化成卷积:
设 \[G_i=\sum_{j>i}\frac{q_j}{(i-j)^2}=\sum_{j=i+1}^n\frac{q_j}{(i-j)^2}\] 令\(A_i=q_i,B_i=\frac{1}{i^2}\)
则上式珂变形为: \[G_i=\sum_{j=i+1}^n A_jB_{j-i}\] 看到A和B的下标和不是定值,考虑翻转系数: \[G_i = \sum_{j=i+1}^nA^R_{n-j}B_{j-i}\] 这时下标和是定值了,要化成卷积还要把sigma的上下标换一下:
平移j的取值范围:
\[G_i=\sum_{j=1}^{n-i}A^R_{n-j+i}B_{j}\] 令\(B_0=0\),此时j可以取到0,并将\(G\)翻转 \[G^R_i=\sum_{j=0}^{i}A^R_{i-j}B_j\] 然后做卷积就可以了! 代码: 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88// luogu-judger-enable-o2
const double Pi=acos(-1.0);
const int maxn=4e5+100;
double q[maxn];
int limit=1,rev[maxn];
struct Complex
{
double real,imag;
Complex(double real,double imag):real(real),imag(imag){}
Complex(){}
Complex conj();
}w[maxn],winv[maxn],A[maxn],B[maxn],C[maxn];
inline Complex Complex::conj(){return Complex(real,-imag);}
inline Complex operator+(const Complex& a,const Complex& b){return Complex(a.real+b.real,a.imag+b.imag);}
inline Complex operator-(const Complex& a,const Complex& b){return Complex(a.real-b.real,a.imag-b.imag);}
inline Complex operator*(const Complex& a,const Complex& b){return Complex(a.real*b.real-a.imag*b.imag,a.real*b.imag+a.imag*b.real);}
template<typename T>
inline void swap(T& a,T& b){T t=a;a=b;b=t;}
inline void DFT(Complex* A,Complex* w,int limit)
{
for (register int i=0;i<limit;++i)
if (i<rev[i]) swap(A[i],A[rev[i]]);
for (register int mid=1;mid<limit;mid<<=1)
for (register int R=mid<<1,j=0;j<limit;j+=R)
for (register int k=0;k<mid;++k)
{
Complex x=A[j+k],y=w[limit/mid/2*k]*A[j+mid+k];
A[j+k]=x+y;
A[j+mid+k]=x-y;
}
}
inline void prework(int n)
{
int l=0;
while (limit<=(n<<1)+1) limit<<=1,++l;
for (register int i=0;i<limit;++i)
rev[i]=(rev[i>>1]>>1)|((i&1)<<(l-1));
for (register int i=0;i<limit;++i)
w[i]=Complex(cos(Pi*2/limit*i),sin(Pi*2/limit*i)),winv[i]=w[i].conj();
}
int main()
{
int n;
scanf("%d",&n);
for (int i=1;i<=n;++i)
scanf("%lf",q+i),A[i].real=q[i];
prework(n);
for (int i=1;i<=n;++i)
B[i].real=1.0/i/i;
DFT(A,w,limit);DFT(B,w,limit);
static Complex G[maxn],H[maxn];
for (int i=0;i<limit;++i)
G[i]=A[i]*B[i];
DFT(G,winv,limit);
for (int i=0;i<limit;++i)
G[i].real/=limit;
std::reverse(q,q+n+1);
for (int i=0;i<limit;++i)
A[i]=Complex(q[i],0);
// for (int i=0;i<=n;++i)
// B[i]=Complex(1.0/(i+1)/(i+1),0);
DFT(A,w,limit);
// DFT(B,w,limit);
for (int i=0;i<limit;++i)
H[i]=A[i]*B[i];
DFT(H,winv,limit);
for (int i=0;i<limit;++i)
H[i].real/=limit;
for (int i=1;i<=n;++i)
printf("%.5lf\n",G[i].real-H[n-i].real);
// while (~puts("\a"));
}