P4345 [SHOI2015]超能粒子炮·改 Lucas
阿新 • • 發佈:2019-01-23
isdigit getch 貢獻 原理 span 包含 git 乘法 參數 行,每行兩個整數 \(n\)、\(k\),含義如題面描述。
可以發現,對於\(i\in [0, p*\lfloor\frac k p \rfloor)\)
顯然剩下部分的\(\lfloor \frac i p\rfloor\)
\(\color{#0066ff}{ 題目描述 }\)
曾經發明了腦洞治療儀與超能粒子炮的發明家 SHTSC 又公開了他的新發明:超能粒子炮?改——一種可以發射威力更加強大的粒子流的神秘裝置。
超能粒子炮?改相比超能粒子炮,在威力上有了本質的提升。它有兩個參數\(n\),\(k\),它會向每個編號為\(0\)到\(k\)(包含兩端)的位置\(i\)發射威力為\(C_{n}^{i} mod 2333\)的粒子流。
現在 SHTSC 給出了他的超能粒子炮?改的參數,讓你求出其發射的粒子流的威力之和除以\(2333\)所得的余數。
\(\color{#0066ff}{輸入格式}\)
第一行一個整數\(t\)表示數據組數。 之後 \(t\)
\(\color{#0066ff}{輸出格式}\)
t 行,每行一個整數,表示其粒子流的威力之和模 2333 的值。
\(\color{#0066ff}{輸入樣例}\)
3
5 5
10 7
1145 14
\(\color{#0066ff}{輸出樣例}\)
32
968
763
\(\color{#0066ff}{數據範圍與提示}\)
\(\color{#0066ff}{ 題解 }\)
令\(p=2333, f(n,k)=\begin{aligned}\sum_{i=0}^kC_n^i\end{aligned}\)
考慮將\([0,k]\)分成一些段
可以發現,對於\(i\in [0, p*\lfloor\frac k p \rfloor)\) ,分成了\(\lfloor\frac k p \rfloor\)段,每段長度為p,根據\((\lfloor\frac i p\rfloor, i \% p)\)可以唯一確定一個i
據Lucas定理,有\(C_n^i=C_{n/p}^{i/p}*C_{n\%p}^{i\%p}\)
根據乘法原理,貢獻為\(f(\lfloor\frac n p\rfloor,\lfloor\frac k p\rfloor - 1)*f(n\%p,p-1)\)
考慮剩下的部分,\(i\in[p*\lfloor\frac k p\rfloor,k]\)
顯然剩下部分的\(\lfloor \frac i p\rfloor\) 是一樣的
貢獻為\(C_{n/p}^{k/p}*f(n\%p,k\%p)\)
於是,總貢獻為\(f(n,k)=C_{n/p}^{k/p}*f(n\%p,k\%p)+f(\lfloor\frac n p\rfloor,\lfloor\frac k p\rfloor - 1)*f(n\%p,p-1)\)
預處理出p以內的f值,在預處理階乘和逆元之後,\(O(p^2)\)就能處理,這些值調用比較頻繁
剩下的C直接Lucas就行了
#include<bits/stdc++.h>
#define LL long long
LL in() {
char ch; LL x = 0, f = 1;
while(!isdigit(ch = getchar()))(ch == '-') && (f = -f);
for(x = ch ^ 48; isdigit(ch = getchar()); x = (x << 1) + (x << 3) + (ch ^ 48));
return x * f;
}
const int mod = 2333;
const int maxn = 3e3 + 10;
LL f[maxn][maxn], fac[maxn], inv[maxn];
LL ksm(LL x, LL y) {
LL re = 1LL;
while(y) {
if(y & 1) re = re * x % mod;
x = x * x % mod;
y >>= 1;
}
return re;
}
LL C(LL n, LL m) {
if(m > n || m < 0) return 0;
if(n >= mod || m >= mod) return C(n / mod, m / mod) * C(n % mod, m % mod) % mod;
return ((fac[n] * inv[m] % mod) * inv[n - m]) % mod;
}
LL work(LL n, LL k) {
if(n < mod && k < mod) return f[n][k];
return ((C(n / mod, k / mod) * work(n % mod, k % mod) % mod) + (work(n / mod, k / mod - 1) * work(n % mod, mod - 1) % mod)) % mod;
}
void predoit() {
fac[0] = 1;
for(int i = 1; i < mod; i++) fac[i] = 1LL * i * fac[i - 1] % mod;
inv[mod - 1] = ksm(fac[mod - 1], mod - 2);
for(int i = mod - 2; i >= 0; i--) inv[i] = 1LL * inv[i + 1] * (i + 1) % mod;
for(int i = 0; i < mod; i++) {
f[i][0] = 1;
for(int j = 1; j < mod; j++)
f[i][j] = (f[i][j - 1] + C(i, j)) % mod;
}
}
signed main() {
predoit();
for(int T = in(); T --> 0;) {
LL n = in(), k = in();
printf("%lld\n", work(n, k));
}
return 0;
}
P4345 [SHOI2015]超能粒子炮·改 Lucas