[航海协会]逆天题
Posted StaroForgin
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[航海协会]逆天题相关的知识,希望对你有一定的参考价值。
逆天题
题目概述
题解
首先,我们考虑这东西该怎么用生成函数进行表示。
单纯子集和的生成函数显然就是
∏
i
=
1
m
n
(
1
+
x
i
)
\\prod_i=1^mn(1+x^i)
∏i=1mn(1+xi),如果要求出将子集和取模
n
n
n后得到的
f
i
f_i
fi的话。
有一个经典的技巧就是给整个生成函数取模上一个
x
n
−
1
x^n-1
xn−1的话,就可以将所有的
x
k
n
+
b
x^kn+b
xkn+b的系数叠加到
x
b
x^b
xb上面。
这样,我们就能够求出
f
f
f的生成函数了,也就是
F
=
∏
i
=
0
n
−
1
(
1
+
x
i
)
m
(
m
o
d
x
n
−
1
)
F=\\prod_i=0^n-1(1+x^i)^m \\pmodx^n-1
F=∏i=0n−1(1+xi)m(modxn−1)。
那么我们答案的
∑
f
2
\\sum f^2
∑f2又该怎么求了。
可以观察到这相当于一个子集和减去另一个子集和模
n
n
n为
0
0
0的方案数。
显然,我们子集和的函数是高度对称的,也就是说,减去一个子集需要乘的生成函数就是加上它的生成函数。
所以我们的答案为
[
x
0
]
∏
i
=
0
n
−
1
(
1
+
x
i
)
2
m
(
m
o
d
x
n
−
1
)
[x^0]\\prod_i=0^n-1(1+x^i)^2m \\pmodx^n-1
[x0]∏i=0n−1(1+xi)2m(modxn−1)。
好的,我们又该怎么计算这东西呢?
显然,这个
2
m
2m
2m次方可以做了
D
F
T
DFT
DFT后再次方计算。
由于我们取模的是
x
n
−
1
x^n-1
xn−1,显然
D
F
T
DFT
DFT也就是通过单位根计算的。
可以发现,
1
+
x
i
1+x^i
1+xi再
D
F
T
DFT
DFT后对
x
k
x^k
xk的贡献为
1
+
w
n
i
k
1+w^ik_n
1+wnik。
那我们上面的式子
D
F
T
DFT
DFT后,可以得到
f
i
^
=
∏
k
=
0
n
−
1
(
1
+
w
n
i
k
)
\\widehatf_i=\\prod_k=0^n-1(1+w^ik_n)
fi
=∏k=0n−1(1+wnik)。
怎么算出这东西的真实值呢?考虑
x
n
−
1
=
∏
(
x
−
w
n
i
)
x^n-1=\\prod(x-w_n^i)
xn−1=∏(x−wni)。
带入
x
=
−
1
x=-1
x=−1,可以得到
f
i
^
=
2
[
2
∣
n
(
n
,
i
)
]
(
n
,
i
)
\\widehatf_i=2[2|\\fracn(n,i)]^(n,i)
fi
=2[2∣(n,i)n](n,i)。
再对这东西乘上
2
m
2m
2m次方,也就是我们答案的
F
^
\\widehatF
F
。
答案再
I
D
F
T
IDFT
IDFT回去可以得到
A
n
s
=
1
n
∑
i
=
0
n
−
1
f
i
^
Ans=\\frac1n\\sum_i=0^n-1 \\widehatf_i
Ans=n1∑i=0n−1fi
显然,这东西只与
(
n
,
i
)
(n,i)
(n,i)的大小有关,也就是说,我们只需要对于
n
n
n的所有因数
d
d
d,算出它的
f
d
^
\\widehatf_d
fd
以及
ϕ
(
n
d
)
\\phi(\\fracnd)
ϕ(dn)表示它的出现次数,就刻意知道它的答案了。
n
n
n的因数肯定不会太多,但是要怎么求出这些因数呢?
一种方法是将
n
n
n质因数分解后暴力计算。
由于这里的
n
n
n比较大,我们需要利用
Pollard_rho
\\textPollard\\_rho
Pollard_rho算法快速分解。
时间复杂度 O ( n 1 4 + d ( n ) log m ) O\\left(n^\\frac14+d(n)\\log m\\right) O(n41+d(n)logm),其中 d ( n ) d(n) d(n)表示 n n n的因子个数。
源码
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef __int128 Li;
typedef pair<int,int> pii;
#define MAXN 1000005
#define pb push_back
#define mkpr make_pair
#define fir first
#define sec second
#define lson (rt<<1)
#define rson (rt<<1|1)
const int INF=0x3f3f3f3f;
const int mo=998244353;
template<typename _T>
void read(_T &x)
_T f=1;x=0;char s=getchar();
while(s<'0'||s>'9')if(s=='-')f=-1;s=getchar();
while('0'<=s&&s<='9')x=(x<<3)+(x<<1)+(s^48);s=getchar();
x*=f;
template<typename _T>
_T Fabs(_T x)return x<0?-x[航海协会]逆天题