loj #2038. 「SHOI2015」超能粒子炮・改(组合数学)

来源:互联网 发布:移动的网络机顶盒 编辑:程序博客网 时间:2024/05/23 12:09

题目链接:https://loj.ac/problem/2038

推个柿子,根据Lucas定理可得:


然后S可以预处理出2333以下的部分,递归去求解就好了,组合数可以Lucas定理来求。


代码:

#include<bits/stdc++.h>using namespace std;typedef long long ll;const int MOD=2333;ll sum[2335][2335];ll qpow(ll x,ll k){int res=1;while(k){if(k&1)res=res*x%MOD;x=x*x%MOD;k>>=1;}return res;}ll fact[MOD+10],inv[MOD+10];void init(){fact[0]=1;inv[0]=1;for(int i=1;i<=MOD;i++){fact[i]=fact[i-1]*i%MOD;inv[i]=qpow(fact[i],MOD-2);}}ll Lucas(ll n,ll m){ll a,b,res=1LL;while(n&&m){a=n%MOD,b=m%MOD;if(a<b)return 0LL;res=res*fact[a]%MOD*inv[b]%MOD*inv[a-b]%MOD;n/=MOD,m/=MOD;}return res;}ll cal(ll n,ll k){if(k<MOD&&n<MOD)return sum[n][k];ll ans=0;ans+=Lucas(n/MOD,k/MOD)*sum[n%MOD][k%MOD]%MOD;ans%=MOD;if(k>=MOD)ans+=cal(n/MOD,k/MOD-1)*sum[n%MOD][MOD-1]%MOD;ans%=MOD;return ans;}int main(){//freopen("in.txt","r",stdin);//freopen("out.txt","w",stdout);int T;init();for(int i=0;i<MOD;i++){for(int j=0;j<=i;j++){sum[i][j]=Lucas(i,j);}for(int j=1;j<MOD;j++){sum[i][j]+=sum[i][j-1];sum[i][j]%=MOD;}}scanf("%d",&T);while(T--){ll k,n;scanf("%lld%lld",&n,&k);printf("%lld\n",cal(n,k));}return 0;}