存在序列
首先可以尝试随意给定一个序列
不难发现这玩意每一项实际上就是二项式系数,或者说杨辉三角。并且还能发现,对于每一行的元素,它们的系数均相同,不同的只是将下标整体向右平移了一位。
此时我们便可以根据这个性质,求出对于第
显然我们想要算出
显然序列

观察发现,这个东西平移之后,对于大多数的
具体地当我们移动询问区间的时候,遍历所有段,如果某一段的右端点在当前区间内,那么显然指向这一段的组合数会移动到下一段中,所以需要减掉前面的加上现在的。注意移动这步实际上是
于是现在的问题就仅剩如何求
首先还是考虑之前的思路,一定会有很多段的相同的
所以这个东西显然需要快速处理一段组合数,可以考虑做一个组合数的前缀和,这样即可
于是现在问题再次转化为如何快速求这种形式的组合数前缀和,可以参考该题:LG-P4345 [SHOI2015]超能粒子炮·改。
具体地,对于求
然后发现对于前面的
然后继续转化:
此时对比我们之前设的
然后我们只要随便与处理一下
考虑这个东西的复杂度,用主定理推导一下即可:
至此我们就终于完成了这道题。
xxxxxxxxxx115123
45678910
11using namespace std;12
13mt19937 rnd(random_device{}());14int rndd(int l, int r){return rnd() % (r - l + 1) + l;}15bool rnddd(int x){return rndd(1, 100) <= x;}16
17typedef unsigned int uint;18typedef unsigned long long unll;19typedef long long ll;20typedef long double ld;21
2223//7^624
25template < typename T = int >26inline T read(void);27
28int f[10][10];29int N, M, K;30int origin(0);31int sumf[210];32int lucas_div[SPL + 10], lucas_mod[SPL + 10];33struct Blk{int l, r; int val;} blk[210];34
35int qpow(int a, int b){36 int ret(1), mul(a);37 while(b){38 if(b & 1)ret = ret * mul % MOD;39 b >>= 1;40 mul = mul * mul % MOD;41 }return ret;42}43int fact[10], inv[10];44void Init(void){45 fact[0] = 1;46 for(int i = 1; i < MOD; ++i)fact[i] = fact[i - 1] * i % MOD;47 inv[MOD - 1] = qpow(fact[MOD - 1], MOD - 2);48 for(int i = MOD - 2; i >= 0; --i)inv[i] = inv[i + 1] * (i + 1) % MOD;49}50int GetC(int n, int m){51 if(n < m)return 0;52 return fact[n] * inv[m] % MOD * inv[n - m] % MOD;53}54int Lucas(ll n, ll m){55 if(n < MOD && m < MOD)return GetC(n, m);56 return Lucas(n / MOD, m / MOD) * GetC(n % MOD, m % MOD) % MOD;57}58int O1Lucas(ll m){59 return (lucas_div[m / SPL] * lucas_mod[m % SPL]) % MOD;60}61void InitF(void){62 for(int i = 0; i <= MOD - 1; ++i)f[i][0] = f[0][i] = 1;63 for(int i = 1; i <= MOD - 1; ++i)64 for(int j = 1; j <= MOD - 1; ++j)65 f[i][j] = (f[i][j - 1] + Lucas(i, j)) % MOD;66}67int F(ll n, ll k){68 if(n < 0 || k < 0)return 0;69 if(n < MOD && k < MOD)return f[n][k];70 return (f[n % MOD][MOD - 1] * F(n / MOD, k / MOD - 1) % MOD + Lucas(n / MOD, k / MOD) * f[n % MOD][k % MOD] % MOD) % MOD;71}72
73int main(){74 Init(), InitF();75 N = read(), M = read(), K = read();76 for(int i = 0; i <= SPL; ++i)lucas_div[i] = Lucas((N - K) / SPL, i), lucas_mod[i] = Lucas((N - K) % SPL, i);77 int curl(1);78 for(int i = 1; i <= M; ++i)blk[i].val = read(), blk[i].l = curl, blk[i - 1].r = blk[i].l - 1, curl += read();79 blk[M].r = N; int lim = N - K + 1;80 for(int i = 1; i <= M; ++i)81 sumf[i] = (F(N - K, blk[i].r - 1) - F(N - K, blk[i].l - 2) + MOD) % MOD;82 for(int i = 1; i <= M; ++i){83 int l = blk[i].l, r = blk[i].r;84 if(l > lim)break;85 if(r <= lim)(origin += sumf[i] * blk[i].val % MOD) %= MOD;86 else (origin += (F(N - K, lim - 1) - F(N - K, l - 2) + MOD) % MOD * blk[i].val % MOD) %= MOD;87 }printf("%d ", origin);88 int cl = 1, cr = lim;89 for(int i = 2; i <= K; ++i){90 for(int m = 1; m <= M; ++m){91 int r = blk[m].r;92 if(cl <= r && r <= cr)93 origin = (origin - O1Lucas(r - cl) * blk[m].val % MOD + O1Lucas(r - cl) * blk[m + 1].val % MOD + MOD) % MOD;94 }++cl, ++cr;95 printf("%d ", origin);96 }printf("\n");97 fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);98 return 0;99}100
101template < typename T >102inline T read(void){103 T ret(0);104 int flag(1);105 char c = getchar();106 while(c != '-' && !isdigit(c))c = getchar();107 if(c == '-')flag = -1, c = getchar();108 while(isdigit(c)){109 ret *= 10;110 ret += int(c - '0');111 c = getchar();112 }113 ret *= flag;114 return ret;115}update-2022_12_02 初稿