bzoj 3622: 已经没有什么好害怕的了

2333给神题跪烂。。

简直是什么鬼。。

%%%    http://www.cnblogs.com/dyllalala/p/3900077.html

这个题比较好的是,直接算是不好算的(没法算吧,反正我不会),然而算出来一个规定的序列的是很简答的。

所以,先把a数组和b数组排序,搞出在排序状态下的f[i][j]表示前 i 个数中满足条件的有 j 个

这样搞出的f[i][j],然后就该上容斥之类的东西了。

设g[i]表示恰好有 i 个满足的,这个时候,一开始的g[i]=f[n][i]*(n-i)!,(其他n-i个位置随便放啊,所以是(n-i)!),然而要注意到的是,现在的g[i]只是满足>=i 的情况,所以还是要减掉一些东西的。

需要减掉的就是>i 的情况,这时候就用已经算好的 g[i+1...n]再乘个组合数就算出来了。

真的是神奇啊2333

这个神题告诉我们:一步搞不动就分两步,不要死磕,,加上一个辅助的东西,,就会简单多了。。(说的好轻松啊233)

 1 #include <bits/stdc++.h>
 2 #define LL long long
 3 using namespace std;
 4 
 5 const int maxn=2005;
 6 const int mod=1e9+9;
 7 
 8 int fac[maxn],inv[maxn],n,k,a[maxn],b[maxn],num[maxn];
 9 int f[maxn][maxn],g[maxn];
10 
11 int C(int n, int m) {return (LL)fac[n]*inv[m]%mod*inv[n-m]%mod;}
12 
13 int main()
14 {
15     scanf("%d%d",&n,&k);
16     if (n+k&1)
17     {
18         cout<<"0"<<endl;
19         return 0;
20     }
21     k=n+k>>1;
22     fac[0]=inv[0]=inv[1]=1;
23     for (int i=1; i<=n; i++) fac[i]=(LL)fac[i-1]*i%mod;
24     for (int i=2; i<=n; i++) inv[i]=(LL)(mod-mod/i)*inv[mod%i]%mod;
25     for (int i=2; i<=n; i++) inv[i]=(LL)inv[i-1]*inv[i]%mod;
26     for (int i=1; i<=n; i++) scanf("%d",&a[i]);
27     for (int i=1; i<=n; i++) scanf("%d",&b[i]);
28     sort(a+1,a+n+1); sort(b+1,b+n+1);
29     int orz=0;
30     for (int i=1; i<=n; i++)
31     {
32         while (b[orz+1]<a[i] && orz<n) orz++;
33         num[i]=orz;
34     }
35 //    for (int i=1; i<=n; i++) printf("%d ",num[i]); cout<<endl;
36     for (int i=0; i<=n; i++) f[i][0]=1;
37     for (int i=1; i<=n; i++)
38         for (int j=1; j<=i; j++)
39             f[i][j]=(f[i-1][j]+(LL)f[i-1][j-1]*max(0,(num[i]-j+1))%mod)%mod;
40     for (int i=n; i>=k; i--)
41     {
42         g[i]=(LL)f[n][i]*fac[n-i]%mod;
43         for (int j=i+1; j<=n; j++)
44             g[i]=(g[i]-(LL)C(j,i)*g[j]+mod)%mod;
45     }
46     cout<<g[k]<<endl;
47     return 0;
48 }

 

posted @ 2017-04-19 09:27  ws_ccd  阅读(189)  评论(0编辑  收藏  举报