【gdgzezoi】問題C:シャッフルとスワップ

説明

あなたは、2つの長さはN AとBの01列あるき その数は数B A 1に等しいです。

ところで、あなたはA、Bになりたいです:

  1. セットA1、A2は、...、akがA 1のすべてのインデックスです。
  2. セットB1、B2は、...、BKはB 1の全ての指標です。
  3. A1、A2、...、AKランダムな順序、各配置の確率は!1Kに登場している、このステップがk!異なる結果を生成します。
  4. B1、B2、...、ランダムな順序をbkを、各配置の確率が1Kを登場している!、このステップがk!異なる結果を生成します。
  5. すべて1≤i≤kについては、為替AAIとアビが続きます。

P後そう端部AとBが等しくなる確率係合するように呼ばれています。明らかに、P×(K!)2は、この整数剰余998244353の値を計算する必要があり、整数です。

入力
入力文字列01、それぞれA、Bの二列で構成されてい

出力
出力整数:P×(K!)2mod998244353 。
入力サンプルの
サンプル入力。1
1010
1100です

サンプル入力2
01001
01001

サンプル入力3
101010
010101

サンプル入力4
1101011011110
0111101011101
サンプル出力
サンプル出力1
3

サンプル出力2
4

サンプル出力3
36

出力4サンプル。
932 171 449
HINT
1≦| A | = | B |≤104
番号を含む0,1によってA、組成物Bは、1に等しく、そして少なくとも一つの1を含みます。

40分サブタスク本、満足1≤| A | = | B |≤500

思考

我々は2つのステップに答えを分割することができます:

1.列挙マッチAとB

2.マッチ順序を混乱させる

我々は、操作を完了したと仮定し、私たちはそれぞれのマッチングを計算するための合法的なプログラムを生成することができます期待

変換モデルの試み:所定のマッチングについて、アイアイビビ有向エッジに接続されたから、この図は、最終的にいくつかのリングと複数のストランドから成り見つけることができ、そして鎖は配列固有のものです

E愛=バイ= 1Ai =バイ= 1、M = 1が1つのAI、バイ= 0Ai = 1、バイ= 0、辺の数がE + M、M図ストランド見出すことができるがあると仮定し、複数のリング

F [i]が[j]は、フロントI jを割り当て鎖正規プログラム所望の点を表します

次いで、転移:F [I] [J] =Σu≤ju= 0F [I-1]〜[J-U] /(U + 1)
最終的な答えをe * M *(E + M )! !*Σj≤ej= 0F [M] [J]

コード

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=20077,p=998244353;
const ll top=1e17;
int power(int a,int b)
{
    int ass=1;
    for(;b;b>>=1,a=1ll*a*a%p) if(b&1) ass=1ll*ass*a%p;
    return ass;
}
char A[N],B[N];
int fac[N],unfac[N],val[N],l,n,m,c,ass;
int C(int n,int m)
{
    return 1ll*fac[n]*unfac[m]%p*unfac[n-m]%p;
}
int work(int n,int m,int k)
{
    return 1ll*C(m,k)*fac[k]%p*fac[m-k]%p*fac[m-k]%p*C(m+n,m-k)%p;
} 
int main()
{
    fac[0]=1;
    for(int i=1; i<=N; i++) fac[i]=1ll*fac[i-1]*i%p;
    unfac[N-1]=power(fac[N-1],p-2);
    for(int i=N-1;i;i--) unfac[i-1]=1ll*unfac[i]*i%p;
    scanf("%s%s",A+1,B+1);
    l=strlen(A+1);
    for(int i=1; i<=l; i++)
    {
        if(A[i]=='1'&&B[i]=='0') n++;
        if(A[i]=='1'&&B[i]=='1') m++;
    }
    for(int i=0; i<=n; i++) val[i]=1ll*C(n,i)*power(i,n)%p;
    for(int k=0; k<=m; k++)
    {
        ll tmp=0;
        for(int i=0; i<=n; i++)
        {
            if((n-i)&1) tmp-=val[i];else tmp+=val[i];
            if(tmp<-top||tmp>top) tmp%=p;
        }
        tmp=(tmp%p+p)%p;
        ass=(ass+1ll*fac[n]*tmp%p*work(n,m,k))%p;
        for(int i=0; i<=n; i++) val[i]=1ll*val[i]*i%p;
    }
    printf("%d\n",ass);
}

703元記事公開 ウォンの賞賛392 ビューに14万+を

おすすめ

転載: blog.csdn.net/Eric1561759334/article/details/100786874