存在序列
首先可以尝试随意给定一个序列
不难发现这玩意每一项实际上就是二项式系数,或者说杨辉三角。并且还能发现,对于每一行的元素,它们的系数均相同,不同的只是将下标整体向右平移了一位。
此时我们便可以根据这个性质,求出对于第
显然我们想要算出
显然序列
观察发现,这个东西平移之后,对于大多数的
具体地当我们移动询问区间的时候,遍历所有段,如果某一段的右端点在当前区间内,那么显然指向这一段的组合数会移动到下一段中,所以需要减掉前面的加上现在的。注意移动这步实际上是
于是现在的问题就仅剩如何求
首先还是考虑之前的思路,一定会有很多段的相同的
所以这个东西显然需要快速处理一段组合数,可以考虑做一个组合数的前缀和,这样即可
于是现在问题再次转化为如何快速求这种形式的组合数前缀和,可以参考该题:LG-P4345 [SHOI2015]超能粒子炮·改。
具体地,对于求
然后发现对于前面的
然后继续转化:
此时对比我们之前设的
然后我们只要随便与处理一下
考虑这个东西的复杂度,用主定理推导一下即可:
至此我们就终于完成了这道题。
xxxxxxxxxx
1151
2
3
4
5
6
7
8
9
10
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
22
23//7^6
24
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 初稿