题目传送

首先对两个数组排序。

然后预处理出数组p[i]表示b[x]<a[i]的最大的x。

然后我们设f[i][k]表示对于前i个派,我单独选出来k组a[y]>b[y]。(即此时有k组a>b的匹配,其余还未匹配)

显然f[i][k]=f[i-1][k]+f[i-1][k-1]*(p[i]-(k-1))。等号右边的第一项相当于考虑a[i]不分配b,第二项相当于a[i]分配b。

这里还要注意一下f[0][0]=f[1][0]=f[2][0]=...=ff[n][0]=1的边界条件。

但是这个数组肯定不是答案。因为这里f[i][k]中保证了只考虑到A的前i个,B的所有位置,并且满足只给A>B的k个A分配了B, 其余A和B没有配对。

我们可以再设g[i]表示对于前n个派,恰好有i组a[x]>b[x]的方案数。

借助容斥原理思考一番后,可得转移方程:

  g[i]=f[n][i]*(n-i)!-  g[j]*c(j,i)   (i+1<=j<=n,c是组合数)。

这里等号右边的第一项相当于只分配了B的i个A的方案数*没分配B的(n-i)个A分配B的方案数(阶乘项)。这是是所有a>b的匹配对数>=i对的方案数,但注意这里可能会出现同一种分配多次出现的情况(比如3个位置,1、2分配了1、2  ,  3对应3;1、3分配了1、3  ,  2对应2),所以要减掉的g[j]还要乘上个组合数来减掉重复出现的方案数。

考虑最终答案是什么。“A 做的苹果派比 B 做的苹果派美味的天数比 B 做的比 A 做的美味的天数恰好多 k。”设A 做的苹果派比 B 做的苹果派美味的天数为x, B 做的比 A 做的美味的天数为y。则有方程组:

x+y=n;

x-y=k;

解得x=(n+k)/2

由此知道的答案即为g[(n+k)/2],同时知道当(n+k)为奇数时是无解的。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 
 5 using namespace std;
 6 
 7 const int N=2005;
 8 
 9 typedef long long LL;
10 
11 const LL mod=1e9+9;
12 
13 int n,k,a[N],b[N],p[N],s;
14 
15 LL jc[N],f[N][N],g[N],c[N][N];
16 
17 char ch;
18 
19 inline int read()
20 {
21     int x=0;
22     ch=getchar();
23     while(!isdigit(ch)) 
24         ch=getchar();
25     while(isdigit(ch))
26         x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
27     return x;
28 }
29 
30 inline void init()
31 {
32     jc[0]=jc[1]=1;
33     for(int i=2;i<=n;++i)
34         jc[i]=jc[i-1]*i%mod;
35     c[0][0]=1;
36     for(int i=1;i<=n;++i)
37     {
38         c[i][0]=1;
39         for(int j=1;j<=i;++j)
40             c[i][j]=(c[i-1][j-1]+c[i-1][j])%mod;
41     }
42 }
43 
44 int main()
45 {
46     n=read(),k=read();
47     for(int i=1;i<=n;++i)
48         a[i]=read();
49     for(int i=1;i<=n;++i)
50         b[i]=read();
51     if((n+k)&1)
52     {
53         cout<<0;
54         return 0;
55     }
56     s=(n+k)>>1;
57     sort(a+1,a+1+n);
58     sort(b+1,b+1+n);
59     int las=0;
60     for(int i=1;i<=n;++i)
61     {
62         while(b[las+1]<a[i]&&las+1<=n)
63             las++;
64         p[i]=las;
65     }
66     init();
67     f[0][0]=1;
68     for(int i=1;i<=n;++i)
69     {
70         f[i][0]=1;
71         for(int j=1;j<=i;++j)
72             f[i][j]=(f[i-1][j]+f[i-1][j-1]*(p[i]-j+1))%mod;
73     }
74     g[n]=f[n][n];
75     for(int i=n-1;i>=s;--i)
76     {
77         g[i]=f[n][i]*jc[n-i]%mod;
78         for(int j=i+1;j<=n;++j)
79             g[i]=(g[i]-g[j]*c[j][i])%mod;
80         if(g[i]<0)
81             g[i]+=mod;
82     }
83     printf("%lld",g[s]);
84     return 0;
85 }
AC代码

相关文章:

  • 2021-10-01
  • 2021-06-10
  • 2021-06-02
  • 2021-06-22
  • 2022-02-02
  • 2021-06-12
  • 2021-07-25
  • 2021-09-16
猜你喜欢
  • 2021-09-29
  • 2021-11-15
  • 2021-07-28
  • 2022-02-20
  • 2021-08-15
  • 2021-09-13
  • 2021-09-04
相关资源
相似解决方案