[JZOJ5135]逆序對/[HackerRank-101hack43]K-Inversion Permutations

題目大意

給定n,k ,請求出長度爲n 的逆序對數恰好爲k 的排列的個數。
答案對109+7 取模。

1n,k105,1k(n2)


題目分析

首先問題可以轉化成,你有n 個變量aiai 的取值範圍是[0,i1]
你要計算出使得ni=1ai=k 成立的取值方案。
這個怎麼計算呢?有下面兩種方法,不過其實殊途同歸。

容斥原理

考慮使用容斥,我們限制一些aii
設我們限制的aiii 之和爲s ,根據擋板原理,方案數就是(ks+n1n1) 。如果我們限制了mai ,那麼我們就要乘上容斥係數(1)m
雖然總的方案有2n 種,但是實際上,如果我限制的aii 之和超過了k ,它對答案是沒有貢獻的。也就是我只需要計算:在1n 中選出若干個數,使其和爲1k 然後限制個數爲特定奇偶性的方案數。

生成函數

題目實際上是求

[xk](i=1n(1xi))j0(j+n1n1)xj

我們可以枚舉j ,用組合數計算出相應的係數,然後計算前面的累乘裏面相應的i 對應的係數。
累乘裏面的式子是有組合意義的,與上面容斥原理推出來的一致。

計算方案數

於是現在的問題就變成了怎麼計算在1n 中選出若干個數,使其和爲1k 然後限制個數爲特定奇偶性的方案數。這其實是一個經典問題。
腦補一下這樣一個構造過程:一開始什麼數都沒有。對已有的數,我們有兩種操作,一種是全部加1 ,一種是全部加1 然後再加入一個值爲1 的數。這樣執行若干次操作之後構造出來的數列一定滿足條件。
於是我們就可以寫出這樣的方程:設fi,j 表示已經選擇了i 個數,目前的和爲j 的方案,有如下幾種轉移:

fi,j=fi1,ji+fi,ji,fi1,j(n+1),jijn+1

注意到第一維我最多能夠選擇的數的個數顯然是O(k) 級別的,因此時空複雜度是O(kk) 的。
於是本題就完美解決了。

代碼實現

#include <iostream>
#include <cstdio>
#include <cmath>

using namespace std;

const int P=1000000007;
const int N=100050;
const int L=N<<1;
const int M=448;

int fact[L],invf[L];
int n,K,l,m,ans;
int f[M][N];

int quick_power(int x,int y)
{
    int ret=1;
    for (;y;y>>=1,x=1ll*x*x%P) if (y&1) ret=1ll*ret*x%P;
    return ret;
}

void pre()
{
    fact[0]=1;
    for (int i=1;i<=l;++i) fact[i]=1ll*fact[i-1]*i%P;
    invf[l]=quick_power(fact[l],P-2);
    for (int i=l;i>=1;--i) invf[i-1]=1ll*invf[i]*i%P;
}

int C(int n,int m){return 1ll*fact[n]*invf[m]%P*invf[n-m]%P;}

void dp()
{
    f[0][0]=1;
    for (int i=1;i<=m;++i)
        for (int j=0;j<=K;++j)
        {
            if (j>=i) f[i][j]=(f[i][j-i]+f[i-1][j-i])%P;
            if (j>=n+1) f[i][j]=(f[i][j]-f[i-1][j-(n+1)]+P)%P;
        }
}

void calc()
{
    ans=0;
    for (int i=0;i<=m;++i)
        for (int k=0;k<=K;++k)
            (ans+=(((i&1)?-1ll:1ll)*f[i][k]*C(K-k+n-1,n-1)%P+P)%P)%=P;
}

int main()
{
    freopen("inverse.in","r",stdin),freopen("inverse.out","w",stdout);
    scanf("%d%d",&n,&K),l=n+K,m=trunc(sqrt(K*2-1)),pre(),dp(),calc(),printf("%d\n",ans);
    fclose(stdin),fclose(stdout);
    return 0;
}
發佈了227 篇原創文章 · 獲贊 42 · 訪問量 19萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章