[航海协会]逆天题

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 xn1的话,就可以将所有的 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=0n1(1+xi)m(modxn1)

那么我们答案的 ∑ 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=0n1(1+xi)2m(modxn1)

好的,我们又该怎么计算这东西呢?
显然,这个 2 m 2m 2m次方可以做了 D F T DFT DFT后再次方计算。
由于我们取模的是 x n − 1 x^n-1 xn1,显然 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=0n1(1+wnik)
怎么算出这东西的真实值呢?考虑 x n − 1 = ∏ ( x − w n i ) x^n-1=\\prod(x-w_n^i) xn1=(xwni)
带入 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=n1i=0n1fi
显然,这东西只与 ( 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[航海协会]逆天题

[航海协会]求和

[航海协会]基因切割

[航海协会]万灵药

[航海协会]SSSP

[航海协会]稀疏阶乘问题