• BZOJ


    题目

    传送门

    为了方便表示,令 “糖果” 为 (a),“药片” 为 (b)

    解法

    首先 (nequiv kpmod 2),不然是无解的。不过好像没有这种数据(

    由于没有重复的数字,我们可以确定 (a>b) 的组数为 (s=frac{n+k}{2})

    然后有一个比较神仙的 (mathtt{dp}):将 (a,b) 分别进行排序,令 (dp_{i,j}) 为前 (i)(a)至少(j)(a>b) 的方案数。注意,我们 钦定(a<b) 的匹配种类没有被计算。有:

    [dp_{i,j}=dp_{i-1,j}+dp_{i-1,j-1} imes max{0,lst_i-(j-1)} ]

    其中 (lst_i) 为小于 (a_i)(b) 的个数。后面乘上的那一坨就是使 (a_i>b) 的还未匹配的 (b) 的个数。

    另外,(max) 实际上可以去掉,因为当 (lst_i-(j-1)<0) 时,(dp_{i-1,j-1}) 必为 (0)

    (f_i=dp_{n,i} imes (n-i)!),这样 (f_i) 就计算上了 钦定(a<b) 的匹配种类。

    (g_i) 为所有 (a)恰好(i)(a>b) 的方案数。发现对于 (ige m)(f_m) 中计算了 ( ext{C}(i,m))(g_i)。考虑套用二项式反演,有:

    [g_s=sum_{i=s}^n (-1)^{i-s}cdot ext{C}(i,s)cdot f_i ]

    代码

    #include <cstdio>
    #define print(x,y) write(x),putchar(y)
    
    template <class T>
    inline T read(const T sample) {
    	T x=0; char s; bool f=0;
    	while((s=getchar())>'9' or s<'0')
    		f|=(s=='-');
    	while(s>='0' and s<='9')
    		x=(x<<1)+(x<<3)+(s^48),
    		s=getchar();
    	return f?-x:x;
    }
    
    template <class T>
    inline void write(const T x) {
    	if(x<0) {
    		putchar('-'),write(-x);
    		return;
    	}
    	if(x>9) write(x/10);
    	putchar(x%10^48);
    } 
    
    #include <iostream>
    #include <algorithm>
    using namespace std;
    
    const int mod=1e9+9,maxn=2005;
    
    int n,k,a[maxn],b[maxn],lst[maxn];
    int fac[maxn],ifac[maxn];
    int dp[maxn][maxn];
    
    int inv(int x,int y=mod-2) {
    	int r=1;
    	while(y) {
    		if(y&1) r=1ll*r*x%mod;
    		x=1ll*x*x%mod; y>>=1;
    	}
    	return r;
    }
    
    void init() {
    	fac[0]=1;
    	for(int i=1;i<=maxn-5;++i)
    		fac[i]=1ll*fac[i-1]*i%mod;
    	ifac[maxn-5]=inv(fac[maxn-5]);
    	for(int i=maxn-6;i>=0;--i)
    		ifac[i]=1ll*ifac[i+1]*(i+1)%mod;
    }
    
    int C(int n,int m) {
    	if(n<m) return 0;
    	return 1ll*fac[n]*ifac[m]%mod*ifac[n-m]%mod;
    }
    
    int main() {
    	n=read(9),k=read(9);
    	init();
    	for(int i=1;i<=n;++i)
    		a[i]=read(9);
    	for(int i=1;i<=n;++i)
    		b[i]=read(9);
    	sort(a+1,a+n+1);
    	sort(b+1,b+n+1);
    	int p=0;
    	for(int i=1;i<=n;++i) {
    		while(p+1<=n and b[p+1]<a[i])
    			++p;
    		lst[i]=p;
    	}
    	dp[0][0]=1;
    	for(int i=1;i<=n;++i) {
    		dp[i][0]=1;
    		for(int j=1;j<=n;++j)
    			dp[i][j]=(dp[i-1][j]+1ll*dp[i-1][j-1]*max(0,lst[i]-j+1)%mod)%mod;
    	}
    	int ans=0,tmp=1;
    	k=n+k>>1;
    	for(int i=n;i>=k;--i) {
    		if(i-k&1)
    			ans=(ans-1ll*C(i,k)*dp[n][i]%mod*tmp%mod+mod)%mod;
    		else 
    			ans=(ans+1ll*C(i,k)*dp[n][i]%mod*tmp%mod)%mod;
    		tmp=1ll*tmp*(n-i+1)%mod;
    	}
    	print(ans,'
    ');
    	return 0;
    }
    
  • 相关阅读:
    *Path Sum II
    *Path Sum
    Same Tree
    Symmetric Tree
    hprof网络连接
    gc
    java thread park
    sudo !!
    ecb gud
    jpda
  • 原文地址:https://www.cnblogs.com/AWhiteWall/p/15077331.html
Copyright © 2020-2023  润新知