[agc019e]Shuffle and Swap

来源:互联网 发布:淘宝富光保温杯 编辑:程序博客网 时间:2024/06/08 06:27

前言

计数水平不行了。
居然不会n^2去dp这个模型。

题意

太麻烦了看网站。

DP

假设有x个公用1和y个非公用1。
用图论来理解。
最后一定形成y条链,若干个环。
其中链中的边在序列中要按顺序,环则随意。
环可以先不管。
考虑dp[i,j]表示目前做出来两个i+j的序列,有i个公用1和j个非公用1,区分编号,有顺序,形成j条链的方案数。
有dp[i,j]=dp[i-1,j]*i*j+dp[i,j-1]*j*j。
后面那个比较好理解,就是在最后添加一对非公用,有j^2种方法。(不考虑全局编号,只考虑局部问题的编号,因此目前编号是1~j,子问题编号是1~j-1,如果新的选择一个编号在1~j-1,那么让原本拥有这个编号的变成j即可,是唯一对应方案)。
前面那个呢?i同理是编号方案数,因为链有顺序,所以认为最后这个刚好加到某个链的尾部,然后可以把它和对应的非公用1所在位置调换,就是有顺序了。
最后枚举用了多少公用1来参与链的形成,剩余的随便搞(记得把公用1的编号分成两个集合分配,然后还有位置需要分配)。
复杂度是咸鱼的平方。

#include<cstdio>#include<algorithm>#include<cstring>#define fo(i,a,b) for(i=a;i<=b;i++)#define fd(i,a,b) for(i=a;i>=b;i--)using namespace std;typedef long long ll;const int maxn=10000+10,mo=998244353;char s[maxn];int f[maxn][maxn],fac[maxn],inv[maxn],bz[maxn];int i,j,k,l,t,n,m,ans,x,y;int qsm(int x,int y){    if (!y) return 1;    int t=qsm(x,y/2);    t=(ll)t*t%mo;    if (y%2) t=(ll)t*x%mo;    return t;}int C(int n,int m){    if (n<m||m<0) return 0;    return (ll)fac[n]*inv[m]%mo*inv[n-m]%mo;}int main(){    scanf("%s",s+1);    n=strlen(s+1);    fo(i,1,n)        if (s[i]=='1') y++,bz[i]++;    scanf("%s",s+1);    fo(i,1,n)        if (s[i]=='1'&&bz[i]) x++;    y-=x;    fac[0]=1;    fo(i,1,n) fac[i]=(ll)fac[i-1]*i%mo;    inv[n]=qsm(fac[n],mo-2);    fd(i,n-1,0) inv[i]=(ll)inv[i+1]*(i+1)%mo;    f[0][0]=1;    fo(i,1,y) f[0][i]=(ll)fac[i]*fac[i]%mo;    fo(i,1,x)        fo(j,1,y)            f[i][j]=(ll)((ll)f[i-1][j]*i%mo+(ll)f[i][j-1]*j%mo)*j%mo;    fo(i,0,x)        (ans+=(ll)f[x-i][y]*qsm(fac[i],2)%mo*C(x,i)%mo*C(x+y,i)%mo)%=mo;    (ans+=mo)%=mo;    printf("%d\n",ans);}
原创粉丝点击