NKOJ 2966 (BZOJ 3622)已經沒什麼好害怕的了 (DP+二項式反演)

P2966【2014湖北省隊互測week2】已經沒什麼好害怕的了

問題描述

已經使Modoka有簽訂契約,和自己一起戰鬥的想法後,Mami忽然感到自己不再是孤單一人了呢。
於是,之前的謹慎的戰鬥作風也消失了,在對Charlotte的傀儡使用終曲——Tiro Finale後,Mami面臨着即將被Charlotte的本體喫掉的局面。
這時,已經多次面對過Charlotte的Homura告訴了學OI的你這樣一個性質——Charlotte的結界中有兩種具有能量的元素——一種是“糖果”,另一種是“藥片”,每種各有n個。在Charlotte發動進攻前,“糖果”和“藥片”會兩兩配對,若恰好“糖果”比“藥片”能量大的組數比“藥片”比“糖果”能量大的組數多k組,則在這種局面下,Charlotte的攻擊會丟失,從而Mami仍有消滅Charlotte的可能。你必須根據Homura告訴你的“糖果”和“藥片”的能量的信息迅速告訴Homura這種情況的個數。

輸入格式

第一行兩個整數n,k,含義如題目描述。
接着第二行n個整數,第i個數表示第i個糖果的能量。
第三行n個整數,第j個數表示第j個藥片的能量。

輸出格式

一個整數,表示消滅Charlotte的情況個數。答案可能會很大,所以mod (109+9)

樣例輸入

4 2
5 35 15 45
40 20 10 30

樣例輸出

4

數據範圍:

約定:給出的2*n個能量值兩兩不同
對於10%的數據:1<=n<=10
對於40%的數據:1<=n<=500
對於100%的數據:1<=n<=2000,0<=k<=n


先將AiBi 排序
考慮如何計算恰有K對Ai>Bi 的方案數。

F[i] 表示恰有i 對的方案數,令f[i][j] 表示Ai 的前i 個數有j 對的方案數。
t[i] 表示B 中小於Ai 的數的數量。
那麼有轉移方程f[i][j]=f[i1][j]+f[i1][j1](t[i]j+1)t[i]j+1 表示總共有t[i] 個數可以與A[i] 匹配,而其中已經匹配了j1 個。

然後令G[i]=(ni)!f[n][i] ,注意到,這裏的G[i] 意思是先確定iAx>Bx ,然後剩下的隨便排列。
考慮G[i]F[i] 的關係,能夠推出

G[i]=j=inCjiF[j]

這裏我們考慮對於G[i] ,肯定至少有i 對,但剩下的任意排列可能使得對數增加,同時可能造成重複。因此枚舉總共有多少對,然後考慮重複,對於有j 對的方案,在G[i] 中被重複算的次數恰好就是Cji ,意思是從這j 對中選出i 對作爲一開始在f[n][i] 中確定的i 對。

最後二項式反演得到

F[i]=j=in(1)jiCjiG[j]

總時間複雜度O(n2)

代碼:

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<cstring>
#define N 2005
#define ll long long
using namespace std;
const ll mod=1e9+9;
ll n,m,A[N],B[N],f[N][N],C[N][N],F[N],G[N],fac[N],t[N];
int main()
{
    ll i,j,k;fac[0]=1;
    scanf("%lld%lld",&n,&m);
    for(i=1;i<=n;i++)scanf("%lld",&A[i]);
    for(i=1;i<=n;i++)scanf("%lld",&B[i]);
    if(n+m&1)return puts("0"),0;
    m=(n+m)>>1;
    for(i=1;i<=n;i++)fac[i]=fac[i-1]*i%mod;
    for(i=0;i<=n;i++)C[i][0]=1;
    for(i=1;i<=n;i++)
    for(j=1;j<=i;j++)C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
    sort(A+1,A+n+1);
    sort(B+1,B+n+1);
    for(i=j=1;i<=n;i++)
    {
        while(j<=n&&A[i]>B[j])j++;
        t[i]=j-1;
    }
    for(i=0;i<=n;i++)f[i][0]=1;
    for(i=1;i<=n;i++)
    for(j=1;j<=n;j++)f[i][j]=(f[i-1][j]+f[i-1][j-1]*max(0ll,t[i]-j+1)%mod)%mod;
    for(i=0;i<=n;i++)G[i]=fac[n-i]*f[n][i]%mod;
    for(i=m,k=1;i<=n;i++,k=-k)F[m]+=k*C[i][m]*G[i]%mod,F[m]%=mod;
    printf("%lld",(F[m]+mod)%mod);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章