[XSY 3322][置换+dp]Dexterity

我们很容易发现。R必须为置换。
当A=B=C=0的时候,我们对于L没有限制,只要求R是个置换。
并满足 R 2 = E R^2=E ,采用dp。 f i = f i 1 + ( i 1 ) f i 2 f_i=f_{i-1}+(i-1)*f_{i-2}
最后答案即为 f n n n f_n*n^n
当A,B,C中有一个不为0的时候,L,R都是置换。
并且它们满足式子:
              L A R L B R L C = E \ \ \ \ \ \ \ \ \ \ \ \ \ L^ARL^BRL^C=E
  L C L A R L B R L C L C = E \ L^CL^ARL^BRL^CL^{-C}=E
                L A + C R L B R = E \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ L^{A+C}RL^BR=E
L A + C B L B R L B R = E L^{A+C-B}L^BRL^BR=E
注意到,当我们确定了L,我们想要 L B R L^BR 是任何置换都行。
因此,求出满足条件的L,R的方案数等价于求满足
L A + C B R 2 = E L^{A+C-B}R^2=E
      L A + C B = R 2 \ \ \ \ \ L^{A+C-B}=R^{-2} 的置换
类似的,上面式子等价于
L A + C B = R 2 L^{|A+C-B|}=R^2
我们相当于要求出 L a = R 2 L^a=R^2
接下来我们采用dp解决。
直接解决有点难,我们考虑间接解决。
Z = L a = R 2 Z=L^a=R^2
我们求出 L a L^a Z Z 的方案数t1,
再求出 Z Z 分解成 R 2 R^2 的方案数t2, A n s + = t 1 t 2 Ans+=t1*t2
我们令 f i , j f_{i,j} 表示 Z Z 中j个长度为i的环, L a L^a 有多少种方法可以达到。
注意到, L L 中一个长度为 l l 的环,会被分解成 g c d ( a , l ) gcd(a,l) 个长度为 l g c d ( a , l ) \frac{l}{gcd(a,l)} 的环。
那么,我们枚举第一个点原来在那个大环,有递推式:
f i , j = k = 1 i j [ k g c d ( k , a ) = = i ] ( i j 1 ) ! i ( j g c d ( k , a ) ) ! f i , j g c d ( k , a ) f_{i,j}=\sum_{k=1}^{i*j}[\frac{k}{gcd(k,a)}==i]\frac{(i*j-1)!}{i*(j-gcd(k,a))!}f_{i,j-gcd(k,a)}
我们令 g i , j g_{i,j} 表示 Z Z 中j个长度为i的环有多少中方式分解成 R 2 R^2
注意,这个时候已经确定了次序。
我们有递推式: g i , j = g i , j 1 + ( j 1 ) i g i , j 2 g_{i,j}=g_{i,j-1}+(j-1)*i*g_{i,j-2} (想一想,为什么)
最后,我们令 h i , j = f i , j g i , j h_{i,j}=f_{i,j}*g_{i,j}
背包合并一下即可。
时间复杂度: O ( T n 2 l o g 2 n ) O(Tn^2log_2n)

#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
const int Mod=998244353;
typedef unsigned long long ull;
int n;
ull A,B,C;
#define Maxn 1005
int sum[Maxn];
int fact[Maxn],inv[Maxn];
vector<int> vec[Maxn];
int f[Maxn][Maxn],g[Maxn][Maxn];
int way[Maxn],Ans[Maxn];
int c[Maxn][Maxn];
 
ull gcd(ull a,ull b){
    if(!b)return a;
    return gcd(b,a%b);
}
 
inline int Fast_Pow(int a,int b){
    int ans=1;
    while(b){
        if(b&1)ans=1ll*ans*a%Mod;
        a=1ll*a*a%Mod;
        b>>=1;
    }
    return ans;
}
 
int main(){
    c[0][0]=1;
    for(register int i=1;i<=1000;++i){
        c[i][0]=1;
        for(register int j=1;j<=i;++j){
            c[i][j]=c[i-1][j]+c[i-1][j-1];
            if(c[i][j]>=Mod)c[i][j]-=Mod;
        }
    }
    for(register int i=1;i<=1000;++i){
        g[i][0]=1;
        g[i][1]=i&1;
        for(register int j=2;j<=1000;++j)g[i][j]=(1ll*g[i][j-1]*(i&1)+1ll*g[i][j-2]*(j-1)*i)%Mod;
    }
    fact[0]=1;
    for(int i=1;i<=1000;++i)fact[i]=1ll*fact[i-1]*i%Mod;
    inv[0]=inv[1]=1;
    for(int i=2;i<=1000;++i)inv[i]=1ll*(Mod-Mod/i)*inv[Mod%i]%Mod;
    for(int i=2;i<=1000;++i)inv[i]=1ll*inv[i-1]*inv[i]%Mod;
    int T;
    scanf("%d",&T);
    while(T--){
        memset(Ans,0,sizeof(Ans));
        memset(f,0,sizeof(f));
        scanf("%d%llu%llu%llu",&n,&A,&B,&C);
        for(register int i=1;i<=n;++i)vec[i].clear();
        if(A==0&&B==0&&C==0){
            sum[0]=1;
            for(register int i=1;i<=n;++i){
                sum[i]=sum[i-1];
                if(i>1)sum[i]=(sum[i]+1ll*(i-1)*sum[i-2])%Mod;
            }
            printf("%d\n",1ll*sum[n]*Fast_Pow(n,n)%Mod);
            continue;
        }
        A=A+C;
        if(A>=B)A-=B;
        else A=B-A;
        for(register int i=1;i<=n;++i){
        	int tmp=gcd(A,i);
        	vec[i/tmp].push_back(tmp);
        }
        Ans[0]=1;
        for(register int i=1;i<=n;++i){
            f[i][0]=1;
            for(register int j=1;j<=n/i;++j){
                for(register int k=0;k<vec[i].size();++k)
                    if(j>=vec[i][k])
                        f[i][j]=(f[i][j]+1ll*f[i][j-vec[i][k]]*fact[i*j-1]%Mod*inv[i*(j-vec[i][k])])%Mod;
                    else break;
            }
            for(register int j=0;j<=n/i;++j)way[j]=1ll*f[i][j]*g[i][j]%Mod;
            for(register int j=n;j>=0;--j){
                int ans=0;
                for(register int k=0;k*i<=j;++k)
                    ans=(ans+1ll*Ans[j-k*i]*way[k]%Mod*c[j][i*k])%Mod;
                Ans[j]=ans;
            }
        }
        printf("%d\n",Ans[n]);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/ezoilearner/article/details/84997645
今日推荐