AGC005 D ~K Perm Counting
阿新 • • 發佈:2018-12-10
題意
問N有多少個排列滿足,對於i∈[1,n],有 答案對924844033取模
題解
如果我們算出至少i個位置不滿足這個條件的方案數(令之為f(i)),那我們就可以通過容斥來實現這道題 那麼f(i)怎麼求呢 我們把位置看成點,位置上的數也看成點,把那些不滿足條件的關係看做邊,那麼就成了一個二分圖 如圖是5 2 如果我們把他拉直會怎樣 其實就成了幾條鏈 其實也就是說,只有那些%k相同的彼此間會有影響 我們可以通過一個dp,分開計算每條鏈匹配i條邊的方案數,然後再加起來 不過更巧妙的辦法是把這些看做一條長鏈,只是那些原來的鏈的終止節點不能被匹配,然後答案直接讀取末尾的值 也即是說,定義表示前i個,有j個不滿足條件,當前節點是否選擇 (注意此處轉移時判斷是否是兩條鏈的交界處(即是否真的可以連邊)) 那麼,我們要求的f(i)就是 然後容斥
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int mod=924844033;
const int N=4005;
int n,k;
bool vis[N][2];
bool ed[N];
int tot;
int d[N][N][2];
int f[N];
int fact[N];
int main()
{
//freopen("captain.in","r",stdin);
//freopen("captain.out","w",stdout);
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)
for(int j=0;j<=1;j++)
if(!vis[i][j]){
int len=0;
for(int x=i,y=j;x<=n;x+=k,y^=1)
vis[x][y]=1,len++;
tot+=len;
ed[tot]=1;
}
ed[0]=1;
d[0][0][0]=1;
for(int i=0;i<2*n;i++)
for(int j=0;j<=n;j++){
d[i+1][j][0]=(d[i][j][0]+d[i][j][1])%mod;
if(!ed[i])
d[i+1][j+1][1]=d[i][j][0];
}
for(int i=0;i<=n;i++)
f[i]=(d[2*n][i][0]+d[2*n][i][1])%mod;
fact[0]=1;
for(int i=1;i<=n;i++)
fact[i]=1ll*fact[i-1]*i%mod;
int ans=0;
for(int i=0,j=1;i<=n;i++,j=-j)
ans=((1ll*ans+1ll*j*fact[n-i]*f[i]%mod)%mod+mod)%mod;
printf("%d\n",ans);
}