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的意义是Q1且Q1不存在)等价,那反过来也是等价的。
直观点,我们列出
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=0n−1(−1)i∗f(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=0siz−1C(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题