2016.1.26
试题描述
|
聪聪是一个善良可爱、睿智聪慧的好孩子。聪聪是100%的学霸,这一天她在考数学。聪聪很快做到了最后一道题:“高一八班有n个人,从1到n编号,一次互判作业时,老师随机将作业发到这n个人手中。已知有k个人拿到的不是自己的作业,那么请问有多少种情况符合条件呢?”这么简单的问题聪聪当然会做了,她想考考你,你能不能比她先给出问题的答案呢? |
输入
|
共1行,包含2个整数n和k。
|
输出
|
共1行,包含1个整数,表示答案。由于答案可能很大,请输出答案模10007的余数。
|
输入示例
|
4 3
|
输出示例
|
8
|
其他说明
|
对于30%的数据,0≤k≤n≤10。
另有10%的数据,k=0。 另有10%的数据,k=1。 对于70%的数据,0≤k≤n≤10000。 对于100%的数据,0≤k≤1000000,1≤n≤1000000000。 |
C(n,k)*f[k],其中f[k]表示全错排列第k项。
关键是组合数取模!
在函数C中若b>a则直接返回0!(因为这是定义)
把我坑了半天!
所以得出一个很牛x的结论!
C(a,b)模p不等于0的充要条件是a在p进制下的每一位都不小于b在p进制下对应的位,C(a,b)模p等于0的充要条件是a在p进制下至少有一位小于b在p进制下对应的位!
或者上面那句话不好理解的话也没关系,反正没什么卵用,写代码的时候不要忘了判定就好。
AC代码:
#include<iostream> using namespace std; const int mod=10007; int n,k,f[1000005]; int ans=1; int qpow(int a,int b) { int ret=1; while(b) { if(b&1) (ret*=a)%=mod; b/=2; (a*=a)%=mod; } return ret; } int C(int a,int b) { if(b>a) return 0; if(a-b<b) b=a-b; int s1=1,s2=1; for(int i=1;i<=b;i++) { (s1*=i)%=mod; (s2*=(a-i+1))%=mod; } return (s2*qpow(s1,mod-2))%mod; } void Lucas(int a,int b) { if(!a||!b) return ; Lucas(a/mod,b/mod); (ans*=C(a%mod,b%mod))%=mod; } int main() { scanf("%d%d",&n,&k); Lucas(n,k); f[0]=f[2]=1; for(int i=3;i<=k;i++) { f[i]=( ((i-1)%mod) * ((f[i-1]+f[i-2])%mod) )%mod; } if(k>n) cout<<0; else printf("%d",ans*f[k]%mod); }