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 }