1. 程式人生 > >【bzoj4591】超能粒子炮·改

【bzoj4591】超能粒子炮·改

include limit define d+ line using pre HR stream

Portal-->bzoj4591

Solution

  首先這個模數是一個質數

  然後看一下那個\(k\)\(n\)的範圍。。行吧Lucas定理咯

  但是如果直接求:
\[ \sum\limits_{i=0}^{k}\binom n i \]
  那。。穩穩的T啊。。。所以要化一下式子,我們令\(k=ap+b\)
\[ \begin{aligned} \sum\limits_{i=0}^{k}\binom n i&\equiv \sum\limits_{i=0}^k \binom {i/p} {n/p}\binom {i\% p}{n\%p}(mod\ p)\&\equiv \sum\limits_{i=0}^{ap-1}\binom {i/p} {n/p}\binom {i\% p}{n\%p}+\sum\limits_{i=ap}^{ap+b}\binom {i/p} {n/p}\binom {i\% p}{n\%p}(mod\ p)\&\equiv \sum\limits_{i=0}^{a-1}\binom {i} {n/p}\sum\limits_{i=0}^{p-1}\binom {i}{n\%p}+\binom a {n/p}\sum\limits_{i=0}^b\binom {i}{n\%p} \end{aligned} \]


  然後因為\(p\)比較小(只有\(2333\)真是2333)

  所以我們可以直接暴力處理出\(n,m<=2333\)\(\binom n m\)的的前綴和

  然後對於範圍內的直接調用,範圍外的用上面那個式子遞歸處理就好了

  

  代碼大概長這個樣子:

#include<iostream>
#include<cstdio>
#include<cstring>
#define ll long long
using namespace std;
const int MOD=2333;
ll c[MOD+10][MOD+10],sum[MOD+10][MOD+10
]; ll n,k,T,ans; void prework(int n); ll Lucas(ll n,ll m); ll Min(ll x,ll y){return x<y?x:y;} ll f(ll n,ll k); int main(){ #ifndef ONLINE_JUDGE freopen("a.in","r",stdin); #endif ll a,b; scanf("%lld",&T); prework(MOD); for (int o=1;o<=T;++o){ scanf("
%lld%lld",&n,&k); printf("%lld\n",f(n,k)); } } void prework(int n){ c[0][0]=1; for (int i=1;i<=n;++i){ c[i][0]=1; c[i][i]=1; for (int j=1;j<i;++j) c[i][j]=(c[i-1][j-1]+c[i-1][j])%MOD; } for (int i=0;i<=n;++i){ sum[i][0]=c[i][0]; for (int j=1;j<=n;++j) sum[i][j]=(sum[i][j-1]+c[i][j])%MOD; } } ll Lucas(ll n,ll m){ if (n<m) return 0; if (n<MOD&&m<MOD) return c[n][m]; return c[n%MOD][m%MOD]*Lucas(n/MOD,m/MOD)%MOD; } ll f(ll n,ll k){ if (k<0) return 0; if (n<MOD&&k<MOD) return sum[n][k]; return (f(n/MOD,min(k/MOD-1,n/MOD))*sum[n%MOD][MOD-1]%MOD+Lucas(n/MOD,k/MOD)*sum[n%MOD][k%MOD]%MOD)%MOD; }

【bzoj4591】超能粒子炮·改