[SHOI2015]超能粒子炮·改
阿新 • • 發佈:2018-06-21
str 遞推 msu 數據 一行 lap 整數 return sin
題目描述
曾經發明了腦洞治療儀與超能粒子炮的發明家 SHTSC 又公開了他的新發明:超能粒子炮?改——一種可以發射威力更加強大的粒子流的神秘裝置。
超能粒子炮?改相比超能粒子炮,在威力上有了本質的提升。它有兩個參數 n , k ,它會向每個編號為 0 到 k (包含兩端)的位置 i發射威力為Cni ?mod2333 的粒子流。
現在 SHTSC 給出了他的超能粒子炮?改的參數,讓你求出其發射的粒子流的威力之和除以 2333 所得的余數。
輸入輸出格式
輸入格式:
第一行一個整數 t表示數據組數。 之後 t行,每行兩個整數 n、 k ,含義如題面描述。
輸出格式:
t行,每行一個整數,表示其粒子流的威力之和模 2333 的值。
思路:
我們先看一下樣例(p=5,k=10,m=13)
13 0 1 2 3 4 5 6 7 8 9 10
1 3 0 1 2 3 4 0 1 2 3 4 0
5 2 0 0 0 0 0 1 1 1 1 1 2
我們可以驚奇的發現,這是可以用lucas合並的
為什麽呢?
這麽多重復的(00000)(11111)
明顯可以合並加速
那怎麽合並呢?
我們可以通過預處理組合數的辦法(p只有2333),提前求出組合數c
再求出組合數前綴和S
然後遞推公式是這個:
S(n,k)mod p=[S(n/p,k/p-1)*S(n mod p,p-1)+C(n/p,k/p)*S(n mod p,k mod p)]mod p
再套回去,就出來了
Code:
#include<iostream> #include<cstdio> #define rii register int i #define rij register int j #define rit register int t #define ll long long using namespace std; long long i,j,k,m,n,x,y,z,p=2333,q; long long c[2335][2335],s[2335][2335]; int C(ll x,ll y) { return (x<p)?c[x][y]:C(x/p,y/p)*c[x%p][y%p]%p; } int S(ll n,ll k) { return (n<p)?s[n][k]:(s[n%p][p-1]*S(n/p,k/p-1)+C(n/p,k/p)*s[n%p][k%p])%p; } int main() { c[0][0]=s[0][0]=1; for(rii=1;i<=p;i++) { s[0][i]=1; } for(rii=1;i<=p;i++) { for(rij=0;j<=i;j++) { c[i][j]=(c[i-1][j]+c[i-1][j-1])%p; s[i][j]=(s[i][j-1]+c[i][j])%p; } for(rij=i+1;j<=p;j++) { s[i][j]=s[i][j-1]; } } cin>>q; for(rit=1;t<=q;t++) { scanf("%ld",&n); scanf("%ld",&k); printf("%ld\n",S(n,k)); } }
[SHOI2015]超能粒子炮·改