AtCoder Beginner Contest 247 EX(推式子)
Posted 吃花椒的妙酱
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AtCoder Beginner Contest 247 EX(推式子)相关的知识,希望对你有一定的参考价值。
题意 :给个序列ci,表示每个i初始颜色是ci,问进行交换操作k次,最后序列颜色不变的排列有多少个。(n<=2e5,k<=1e9,有多球同色的情况)
Solution:
\\quad
入手的话,可能我们会考虑交换操作和颜色的关系,交换两个同色的下标无意义,交换不同色的(1,2)(2,3)(3,1)试图去找环,发现并不能抵掉交换操作QAQ。
\\quad
考虑朴素的置换环吧。先连边
i
−
>
p
i
i->p_i
i−>pi(一开始pi就是1-n的升序排列)。显然初始有n个大小为1的置换环。
\\quad
接下来看交换操作,交换两个pi,会使置换环数量+1/-1.
证明(参考官方题解):若交换的两数在同个环内,所在环会分裂成两个。对于
a
1
−
>
a
2
−
>
.
.
.
a
i
.
.
−
>
a
j
.
.
.
−
>
a
n
−
>
a
1
a_1->a_2->...a_i..->a_j...->a_n->a_1
a1−>a2−>...ai..−>aj...−>an−>a1,若交换
p
a
i
和
p
a
j
,会变成
p_a_i和p_a_j,会变成
pai和paj,会变成a_1->a_2->…a_i->a_j+1->a_j+2…->a_n->a_1
和
和
和a_j->a_i+1->a_i+2…->a_j$。
\\quad
若两个数不在同一环内,所在的两个环会合并。显然吧,不证了。。
设k次操作后置换环数量为c,若最后排列要满足 n-c <=k且k-(n-c)%2==0.
前一个不等式表示,k不能小于必要操作次数,后一个式子表示不必要操作需要抵消,因为每次只能+1/-1,那显然不必要操作数要是偶数。(所谓必要就是用最少步骤将置换环数变成c个)。
\\quad
现在考虑各种形态的排列如何满足最后每个i要符合对应的染色ci。考虑将每个i逐步加入。
\\quad
设
f
i
,
j
f_i,j
fi,j表示1~i的排列形成了j个置换环的合法方案数(所谓合法就是每个i的染色都是ci).
\\quad
有转移方程
f
i
,
j
=
f
i
−
1
,
j
−
1
+
f
i
−
1
,
j
∗
∑
k
=
1
i
−
1
[
c
k
=
=
c
i
]
f_i,j=f_i-1,j-1 + f_i-1,j*\\sum_k=1^i-1[c_k==c_i]
fi,j=fi−1,j−1+fi−1,j∗∑k=1i−1[ck==ci]。解释一下,若i成自环,那i直接染ci,否则可以替换掉前面颜色是ci的位置。
然后这个式子可以启发式合并求,类似第一类斯特林数。
∑
i
=
1
n
f
n
,
i
x
i
=
∏
i
=
1
n
(
x
+
c
n
t
i
)
,
c
n
t
i
表示在
i
前面且颜色是
c
i
的数量
\\sum_i=1^nf_n,ix^i=\\prod_i=1^n(x+cnt_i),cnt_i表示在i前面且颜色是ci的数量
∑i=1nfn,ixi=∏i=1n(x+cnti),cnti表示在i前面且颜色是ci的数量。
\\quad
证明的话,目前只会归纳法证。
考虑
∏
i
=
1
n
(
x
+
c
n
t
i
)
\\prod_i=1^n(x+cnt_i)
∏i=1n(x+cnti),设
x
k
x^k
xk的系数为f(n,k).
∏
i
=
1
n
−
1
(
x
+
c
n
t
i
)
\\prod_i=1^n-1(x+cnt_i)
∏i=1n−1(x+cnti),设
x
k
x^k
xk的系数为f(n-1,k),x^k-1的系数为f(n-1,k-1).
则
f
(
n
,
k
)
=
f
(
n
−
1
,
k
−
1
)
+
f
(
n
−
1
,
k
)
∗
c
n
t
n
f(n,k)=f(n-1,k-1) + f(n-1,k)*cnt_n
f(n,k)=f(n−1,k−1)+f(n−1,k)∗cntn系数的转移式与上面计数的转移式相同,且f(i,0)=0.
PS:要从本质的置换环考虑😄。
const int N = 2e5+10;
int a[N],n,cnt[N],s[N],k;
Poly cal(int l,int r)
if(l==r)
return Polys[l],1;
int mid = (l+r)>>1;
return mul(cal(l,mid),cal(mid+1,r));
signed main()
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
#endif
ios;
cin>>n>>k;
_for(i,1,n)
cin>>a[i];
s[i] = cnt[a[i]];
cnt[a[i]]++;
Poly F = cal(1,n);
F.resize(n+1,0);
int ans = 0;
_for(i,1,n)
int t = n - i;
if( t<=k && (k - t)%2==0 ) ans = (ans + F[i])%mod;
cout<<ans;
以上是关于AtCoder Beginner Contest 247 EX(推式子)的主要内容,如果未能解决你的问题,请参考以下文章
AtCoder Beginner Contest 115 题解