聪聪考试 |
难度级别:C; 运行时间限制:1000ms; 运行空间限制:262144KB; 代码长度限制:2000000B |
试题描述
|
聪聪是一个善良可爱、睿智聪慧的好孩子。聪聪是100%的学霸,这一天她在考数学。聪聪很快作到了最后一道题:“高一八班有n我的,从1到n编号,一次互判做业时,老师随机将做业发到这n我的手中。已知有k我的拿到的不是本身的做业,那么请问有多少种状况符合条件呢?”这么简单的问题聪聪固然会作了,她想考考你,你能不能比她先给出问题的答案呢?html |
输入
|
共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。 |
题解:ios
n我的当中有k我的拿到的必定不是本身的做业,咱们只须要考虑k我的没有拿到本身做业的状况,因此咱们能够先来一个dp数组储存到k的全错排列。动规方程是:dp[i]=(i-1)*dp[i-1]+(i-1)*dp[i-2](dp[i]表明i我的,所有拿到的不是本身做业的种类数)。数组
动规方程来源:ide
有一种状况是:假如当前有i我的,咱们能够假设前i-1我的拿到的全都不是本身的做业,那么第i我的拿到的必定是本身的做业,因此咱们可让第i我的的做业与前i-1任意一我的的做业进行交换,就是(i-1)dp[i-1]。spa
还有一种状况:就是假设前i-1我的中有1我的拿到本身的做业,也就是说第i我的必定要与拿到本身的做业的人的做业进行交换,这样算出来就是(i-1)dp[i-2]。code
以上两种状况构成了全部的状况,因此咱们能够获得dp方程:dp[i]=(i-1)*dp[i-1]+(i-1)*dp[i-2]htm
咱们须要从n我的中选取k我的拿到的不是本身的做业,对于每一次选取,都有dp[k]种状况,因此最后答案是dp[k]*C(n,k)。blog
可是因为数据比较大,在处理C(n,k)的时候应该用卢卡斯定理。get
如下是代码:input
1 #include<iostream> 2 #define MAXN 1000000+10 3 using namespace std; 4 const int mod=10007; 5 int qp_mod(int x,int n){ 6 int b=1; 7 while(n>0){ 8 if(n&1)b=b*x%mod; 9 x=x*x%mod; 10 n>>=1; 11 } 12 return b; 13 } 14 int comb(int n,int m){ 15 if(m>n)return 0; 16 if(m==n)return 1; 17 int M=1; 18 for(int i=1;i<=m;i++){ 19 i%=mod; 20 M=M*i%mod; 21 } 22 M=qp_mod(M,mod-2); 23 for(int i=n;i>=n-m+1;i--){ 24 i%=mod; 25 M=M*i%mod; 26 } 27 return M; 28 } 29 int Lucas(int n,int m){ 30 int ans=1; 31 while(n&&m&&ans){ 32 ans=ans*comb(n%mod,m%mod)%mod; 33 n/=mod;m/=mod; 34 } 35 return ans; 36 } 37 int n,k; 38 int dp[MAXN]; 39 int main(){ 40 scanf("%d%d",&n,&k); 41 if(k==0){ 42 cout<<1; 43 return 0; 44 } 45 dp[1]=0;dp[2]=1; 46 for(int i=3;i<=k;i++){ 47 dp[i]=(i-1)%mod*((dp[i-1]+dp[i-2])%mod)%mod; 48 } 49 cout<<Lucas(n,k)*dp[k]%mod; 50 }