21年icpc上海区域赛B题Strange Permutations (容斥+生成函数)

Posted 吃花椒的妙酱

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了21年icpc上海区域赛B题Strange Permutations (容斥+生成函数)相关的知识,希望对你有一定的参考价值。

题意: 求给定n的排列P,求满足对于任意i∈[1,n-1]满足 Q i + 1 ≠ P Q i Q_i+1\\neq P_Q_i Qi+1=PQi的Q排列方案数。(n<=1e5)
Solution: 排列的图意义

\\quad 直接看这个式子有点晕,看到排列可以从图意义入手。
我们设P,Q的图意义为: P Q i − > Q i + 1 P_Q_i->Q_i+1 PQi>Qi+1,当然反过来也一样的(这个意义想了几天,被 i − > P i + 1 i->P_i+1 i>Pi+1的固有套路给框柱了,意义是可以自定义的)。如果考虑i从1到n的话,连出来肯定是若干环,这个和 i − > P i i->P_i i>Pi的建图意义是一样的。
\\quad 乱证一下:因为 P Q i P_Q_i PQi是个排列, Q i + 1 Q_i+1 Qi+1也是个排列(先假设Qn+1有意义),把两个排列按照 Q i + 1 Q_i+1 Qi+1大小排序,就转化成了 i − > P i i->P_i i>Pi
\\quad 然后因为i只从1到n-1,那图是个哈密顿图(哈密顿路径)。因为只有n-1个点有出边,n-1个点有入边,且出入度至多为1,画画图得连出来是个哈密顿图。或者从上面连出来的环意义考虑,首先环是不合法的,因为有环就意味这每个点入出度都为1,显然不对,那还要联通,只能是哈密顿图了。
\\quad 说了这么多就想证,图意义是哈密顿图。那问题转化成图上有n条禁边,求合法的哈密顿路径数量。禁边的可以设成(i,Pi)。
\\quad 为什么这样设是对的呢,上面证了i->Pi的建图意义和 P Q i − > Q i + 1 ( 假设 Q n + 1 的意义是 Q 1 且 Q 1 不存在 ) P_Q_i->Q_i+1(假设Q_n+1的意义是Q_1且Q_1不存在) PQi>Qi+1(假设Qn+1的意义是Q1Q1不存在)等价,那反过来也是等价的。
直观点,我们列出 P Q i P_Q_i PQi Q i + 1 Qi+1 Qi+1
P:3 4 1 2
Q:1 4 3 2
P Q i P_Q_i PQi:3 2 1 4
Q i + 1 Q_i+1 Qi+1: 4 3 2 ?
根据上面的建图意义,这是合法的。
来组不合法的。
P:3 4 1 2
Q:1 3 4 2
P Q i P_Q_i PQi:3 2 1 4
Q i + 1 Q_i+1 Qi+1:3 4 2 ?
3指向3不合法了,发现用 i − > P i i->P_i i>Pi与这个建图意义的禁边意义是相同的!于是就可以转成n条禁边(i,Pi)。而n条禁边组成了若干环,我们要选的是哈密顿回路,所以不能有环。
\\quad 考虑容斥, f ( i ) f(i) f(i)表示钦定选i条禁边的哈密顿路径数,因为不能有环,所以对于禁边组成的若干环,每个环上的边都不能全取,则 a n s = ∑ i = 0 n − 1 ( − 1 ) i ∗ f ( i ) ans=\\sum_i=0^n-1(-1)^i*f(i) ans=i=0n1(1)if(i)(这是二项式反演,但不是没有组合数的容斥系数!容斥系数在后面的多项式计算里体现出来了!所以最外层不用带组合数!!!)。
设每个环多项式为 g ( x ) = ∑ i = 0 s i z − 1 C ( s i z , i ) x i g(x) = \\sum_i=0^siz-1C(siz,i)x^i g(x)=i=0siz1C(siz,i)xi,其中siz为环大小。
设 F = ∏ g j , f ( i ) = [ x i ] F 设F =\\prod g_j, f(i)=[x^i]F F=gj,f(i)=[xi]F,即第i项的系数,F的计算用启发式合并算一下就可以了。
时间复杂度 O ( n l o g 2 n ) O(nlog^2n) O(nlog2n)
这题难点还是在求解问题的转化上。搞清楚后,很容易。
(因为这题结合别的大佬们的题解理解了好久,把一些自己想错的问题都写了,所以比较长,还有一些证明和理解也是自己瞎想的,如有不对的话,还请读者留言区指正,感谢)

#defien int long long
const int N=1e5+5;
const int mod=998244353;
const double eps=1e-8;
const int MAXL = 60;
int n,k;
int a[N];
std::vector<int> G[N];
const int maxn = 6e6+10;
const int p = 998244353;
int Pow(int x,int d)
    int tans = 1;
    if(d == 0)return 1%p;
    int a = Pow(x,d/2);
    tans = 1ll*a*a%p;
    if(d%2)tans = 1ll*tans*x%p;
    return tans%p;

typedef vector<int> Poly;//多项式定义
int F1[maxn],F2[maxn];
int rev[maxn];
void NTT(int * A,int lim,int opt) 
    int i, j, k, m, gn, g, tmp;
    for(int i = 0; i < lim; ++i)rev[i] = (i & 1)*(lim >> 1) + (rev[i >> 1] >> 1);
    for(i = 0; i < lim; ++i)if (rev[i] < i) swap(A[i], A[rev[i]]);
    for(m = 2; m <= lim; m <<= 1) 
        k = m >> 1;
        gn = Pow(3,(p - 1) / m);
        for(i = 0; i < lim; i += m) 
            g = 1;
            for (j = 0; j < k; ++j, g = 1ll * g * gn % p) 
                tmp = 1ll * A[i + j + k] * g % p;
                A[i + j + k] = (A[i + j] - tmp + p) % p;
                A[i + j] = (A[i + j] + tmp) % p;
            
        
    
    if(opt == -1)
        reverse(A+1,A+lim);
        int inv = Pow(lim,p-2);
        for(i = 0; i < lim; ++i) A[i] = 1ll * A[i] * inv % p;
    

Poly operator + ( const Poly &A,const Poly &B)
    int n = A.size() , m = B.size();
    int siz = max(n,m);
    Poly C(siz,0);
    for(int i=0 ;i<siz ;i++)
        if( i <n && i < m) C[i] = (A[i] + B[i])%p;
        else if( i < n ) C[i] = A[i];
        else C[i] = B[i];
    
    return C;

Poly mul(const Poly & A,const Poly & B)
    int n = A.size(),m = B.size();
    int siz = n + m - 1;
    Poly C(siz);
    if(siz < 64)//小于等于64项直接暴力算
        for(int i =以上是关于21年icpc上海区域赛B题Strange Permutations (容斥+生成函数)的主要内容,如果未能解决你的问题,请参考以下文章

第 46 届国际大学生程序设计竞赛(ICPC)亚洲区域赛(上海),签到题6题

第 46 届国际大学生程序设计竞赛(ICPC)亚洲区域赛(上海),签到题6题

第 45 届国际大学生程序设计竞赛(ICPC)亚洲区域赛(上海),签到题5题

第 45 届国际大学生程序设计竞赛(ICPC)亚洲区域赛(上海),签到题5题

ICPC2021上海区域赛 B.Mine Sweeper II(思维构造)

ICPC2021上海区域赛 D.Walker(二分分类讨论)