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,会变成 paipaj,会变成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=fi1,j1+fi1,jk=1i1[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=1n1(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(n1,k1)+f(n1,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 234

AtCoder Beginner Contest 115 题解

AtCoder Beginner Contest 154 题解

AtCoder Beginner Contest 103

AtCoder Beginner Contest 228

AtCoder Beginner Contest 242