首页 > 代码库 > Bzoj4870 [SXOI2017]组合数问题

Bzoj4870 [SXOI2017]组合数问题

Time Limit: 10 Sec  Memory Limit: 512 MB
Submit: 155  Solved: 78

Description

技术分享

Input

第一行有四个整数 n, p, k, r,所有整数含义见问题描述。
1 ≤ n ≤ 10^9, 0 ≤ r < k ≤ 50, 2 ≤ p ≤ 2^30 − 1

Output

一行一个整数代表答案。

Sample Input

2 10007 2 0

Sample Output

8

HINT

 

Source

黑吉辽沪冀晋六省联考

 

数学问题 组合数

震惊!考场上花式骗分竟然可以拿到80分!

正解:

  这个东西当然没有什么既成的公式,需要用DP推公式,和平常的公式推DP正好反过来了。

  发现这个式子的项覆盖了nk内所有%k==r的位置,那么可以考虑这个式子的组合意义——

  在全部nk个物品中,选出任意个物品使得选出的物品数%k==r的方案数!

  设f[考虑到第i个物品][选出数量%k==j]=方案数,于是变成了可以$O(n^3)$推出来的背包问题?

  还可以更加简单粗暴,$f[2n][(i+j)%k]=\sum f[n][i]*f[n][j] $ $O(n^2 logn)$倍增出解。

 

 1 /*by SilverN*/ 2 #include<iostream> 3 #include<algorithm> 4 #include<cstring> 5 #include<cstdio> 6 #include<cmath> 7 #include<vector> 8 #define LL long long 9 using namespace std;10 const int mxn=100010;11 int read(){12     int x=0,f=1;char ch=getchar();13     while(ch<0 || ch>9){if(ch==-)f=-1;ch=getchar();}14     while(ch>=0 && ch<=9){x=x*10-0+ch;ch=getchar();}15     return x*f;16 }17 int n,P,k,r;18 struct num{19     int x[52];20     void init(){21         memset(x,0,sizeof x);22     }23 }f;24 num calc(const num &a,const num &b){25     num res;26     res.init();27     for(int i=0;i<=k;i++)28         for(int j=0;j<=k;j++)29             (res.x[(i+j)%k]+=(LL)a.x[i]*b.x[j]%P)%=P;30     return res;31 }32 num ksm(num a,LL t){33     num res;34     res.init();res.x[0]=1;35     while(t){36         if(t&1)res=calc(res,a);37         a=calc(a,a);38         t>>=1;39     }40     return res;41 }42 int main(){43     int i,j;44     n=read();P=read();k=read();r=read();45     f.x[0]=1;46     f.x[1%k]+=1;47     f=ksm(f,(LL)n*k);48 //    for(i=0;i<=k;i++)printf("%d\n",f.x[i]);49     printf("%d\n",f.x[r]);50     return 0;51 }

 

Bzoj4870 [SXOI2017]组合数问题