UVA 11806 - Cheerleaders
我的思路一点都没错,就是求组合的时候出了点错T T
直接容斥原理就好了。
设A(去掉最后一行)B(去掉最上面一行)C(去掉最右边一行)D(去掉最左边一行)
Ans= A∪B∪C∪D
-A-B-C-D
+ A∩B + A∩C + A∩D + B∩C + B∩D + C∩D
- A∩B∩C- A∩B∩D- A∩C∩D - B∩C∩D
+ A∩B∩C∩D
我把它分行了,这样比较好看^ ^
整理可得:(设组合数为c(n,k) )
ans=c(m * n,k)
-2* c(m * (n-1), k ) - 2 * c( n * (m-1),k)
+c(n * (m-2),k) +c( (n-2) * m,k) + 4 * c((n-1) * (m-1),k)
-2* c((m-2) * (n-1),k) -2 * c((m-1) * (n-2),k)
+c( (m-2) * (n-2),k)
嗯,接下来只要求组合数就可以啦~
来看看一段求组合数的代码:
运用了c(n,k)=(n-k+1) / k *c(n,k-1)
int c(long long n,long long k) //思路是没有错的,但是过程不对,mod运算不对/封闭。 { if(n==0||n<k) return 0; if(k>n/2) k=n-k; long long ans=1; for(long long i=1;i<=k;i++) ans=ans*(n-i+1)/i % mod; return ans % mod; }
思路是没有错的,但是过程不对,mod运算不对/封闭。
想想Mod运算:
(a+b)% c=(a % c + b % c) % c
(a-b)% c=( a % c –b % c +c) % c //你无法保证a % c > b %c
(ab)% c=( a %c ) * ( b%c ) % c
但是没有除法!!!
那么,要如何求呢?可以运用
C(n,k)=C(n-1,k-1)+C(n-1,k)
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> using namespace std; #define c(n,k) (C[n][k]) const int mod=1000007; const int MAXK = 500; int C[MAXK+10][MAXK+10]; int main() { memset(C,0,sizeof(C)); C[0][0] = 1; //没有直接WA for(int i=1;i<=MAXK;i++) { C[i][0]=C[i][i]=1; for(int j=1;j<i;j++) C[i][j]=(C[i-1][j-1]+C[i-1][j]) %mod; } int repeat; scanf("%d",&repeat); for(int ri=1;ri<=repeat;ri++) { int n,m,k,ans; scanf("%d%d%d",&m,&n,&k); ans=((((c(m * n,k) % mod -2 * c(m * (n-1), k ) % mod - 2 * c( n * (m-1),k) % mod + 4*mod ) % mod + c(n * (m-2),k) % mod +c( (n-2) * m,k) % mod + 4 * c((n-1) * (m-1),k) % mod ) %mod -2 * c((m-2) * (n-1),k) % mod - 2 * c((m-1) * (n-2),k) % mod +4*mod )%mod + c( (m-2) * (n-2),k) % mod ) %mod ; printf("Case %d: %d\n",ri,ans); } }
新 blog : www.hrwhisper.me