BZOJ3622 已经没有什么好害怕的了

来源:互联网 发布:淘宝抠图视频 编辑:程序博客网 时间:2024/04/28 05:27

KuribohG神犇说过,看到计数想容斥

先把两个数组排序,然后f[i][j]表示从a数组中的前i个里选j个,b数组里任选j个,满足选出来的数两两配对a里的都比b里的大的方案数,因为a数组有序了,所以转移也很简单,然后求出了f[n][i]之后容斥,设g[i]为a和b里所有数两两配对,恰好有i对a里的比b里的大的方案数,则g[i]=f[n][i]*(n-i)! -sigma j=i+1 to n (C(j,i)*g[j])

#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<ctime>#include<cmath>#include<algorithm>#include<iomanip>#include<vector>#include<map>#include<set>#include<bitset>#include<queue>#include<stack>using namespace std;#define MAXN 2010#define MAXM 1010#define INF 1000000000#define MOD 1000000009#define eps 1e-8#define ll long longint a[MAXN];int b[MAXN];int n,K;ll f[MAXN][MAXN];ll ans;ll fac[MAXN],ine[MAXN];int find(int x){int l=0,r=n;int re;while(l<=r){int mid=l+r>>1;if(b[mid]<x){re=mid;l=mid+1;}else{r=mid-1;}}return re;}ll C(int n,int m){return fac[n]*ine[m]%MOD*ine[n-m]%MOD;}ll mi(ll x,ll y){ll re=1;while(y){if(y&1){(re*=x)%=MOD;}(x*=x)%=MOD;y>>=1;}return re;}int main(){int i,j,k;scanf("%d%d",&n,&K);if((n+K)&1){printf("%d\n",0);return 0;}fac[0]=ine[0]=ine[1]=1;for(i=1;i<=n;i++){fac[i]=fac[i-1]*i%MOD;}for(i=2;i<=n;i++){ine[i]=(MOD-MOD/i)*ine[MOD%i]%MOD;}for(i=2;i<=n;i++){(ine[i]*=ine[i-1])%=MOD;}for(i=1;i<=n;i++){scanf("%d",&a[i]);}for(i=1;i<=n;i++){scanf("%d",&b[i]);}sort(a+1,a+n+1);sort(b+1,b+n+1);int t=find(a[1]);f[1][0]=1;f[1][1]=t;for(i=2;i<=n;i++){f[i][0]=f[i-1][0];int t=find(a[i]);for(j=1;j<=min(t+1,i);j++){f[i][j]=(f[i-1][j]+(ll)f[i-1][j-1]*(t-j+1)%MOD)%MOD;}}t=(n+K)/2;for(i=n;i>=t;i--){f[n][i]=f[n][i]*fac[n-i]%MOD;for(j=i+1;j<=n;j++){(f[n][i]+=MOD-C(j,i)*f[n][j]%MOD)%=MOD;}}printf("%lld\n",f[n][t]);return 0;}/*4 25 35 15 4540 20 10 30*/


0 0
原创粉丝点击