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
先將 和 排序
考慮如何計算恰有K對 的方案數。
令 表示恰有 對的方案數,令 表示 的前 個數有 對的方案數。
令 表示 中小於 的數的數量。
那麼有轉移方程 , 表示總共有 個數可以與 匹配,而其中已經匹配了 個。
然後令 ,注意到,這裏的 意思是先確定 對 ,然後剩下的隨便排列。
考慮 與 的關係,能夠推出
這裏我們考慮對於 ,肯定至少有 對,但剩下的任意排列可能使得對數增加,同時可能造成重複。因此枚舉總共有多少對,然後考慮重複,對於有 對的方案,在 中被重複算的次數恰好就是 ,意思是從這 對中選出 對作爲一開始在 中確定的 對。
最後二項式反演得到
總時間複雜度
代碼:
#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);
}