bzoj 4591 超能粒子炮·改

Description

曾经发明了脑洞治疗仪&超能粒子炮的发明家SHTSC又公开了他的新发明:超能粒子炮·改--一种可以发射威力更加
强大的粒子流的神秘装置。超能粒子炮·改相比超能粒子炮,在威力上有了本质的提升。它有三个参数n,k。它会
向编号为0到k的位置发射威力为C(n,k) mod 2333的粒子流。现在SHTSC给出了他的超能粒子炮·改的参数,让你求
其发射的粒子流的威力之和模2333。

Input

第一行一个整数t。表示数据组数。
之后t行,每行二个整数n,k。含义如题面描述。
k<=n<=10^18,t<=10^5

Output

t行每行一个整数,表示其粒子流的威力之和模2333的值。

Sample Input

1
5 5

Sample Output

32

HINT

 

Source

题目大意

  给定$n, k$,求$sum_{i = 0} ^{k}C_{n}^{i}$模2333的余数。

  显然Lucas。

  $sum_{i = 0} ^{k}C_{n}^{i}\ =sum_{i = 0} ^ {k}C_{n \% p}^{i\% p}C_{left lfloor frac{n}{p}  ight floor}^{left lfloor frac{i}{p} ight floor}\ =left (sum_{i = 0}^{p}C_{n \% p}^{i\% p}  ight )left ( sum_{i = 0}^{left lfloor frac{k}{p} ight floor - 1} C_{left lfloor frac{n}{p} ight floor} ^ {left lfloor frac{i}{p} ight floor} ight ) + C_{left lfloor frac{n}{p} ight floor}^{left lfloor frac{k}{p} ight floor}left ( sum_{i = 0}^{k \% p}C_{n \% p}^{i} ight )$

  考虑中间的一步可以进行递归计算。又因为$p = 2333$,所以最后一个前缀和可以预处理。

  会出现一个较大的组合数,可以直接用Lucas算。

  其实它可先用Lucas预处理,这样可以少个log。

Code

 1 /**
 2  * bzoj
 3  * Problem#4591
 4  * Accepted
 5  * Time: 4140ms
 6  * Memory: 44008k
 7  */
 8 #include <bits/stdc++.h>
 9 #ifndef WIN32
10 #define Auto "%lld"
11 #else
12 #define Auto "%I64d"
13 #endif
14 using namespace std;
15 typedef bool boolean;
16 #define ll long long
17 
18 const int p = 2333;
19 
20 ll n, k;
21 
22 int pow2[p + 5];
23 int C[p + 5][p + 5];
24 int sc[p + 5][p + 5];
25 
26 inline void prepare() {
27     pow2[0] = 1;
28     for (int i = 1; i < p; i++)
29         pow2[i] = (pow2[i - 1] << 1) % p;
30     
31     C[0][0] = 1;
32     for (int i = 1; i < p; i++) {
33         C[i][0] = C[i][i] = 1; 
34         for (int j = 1; j < i; j++)
35             C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) % p; 
36     }
37     
38     for (int i = 0; i < p; i++) {
39         sc[i][0] = 1;
40         for (int j = 1; j < p; j++)
41             sc[i][j] = (sc[i][j - 1] + C[i][j]) % p; 
42     }
43 }
44 
45 inline void init() {
46     scanf(Auto""Auto, &n, &k);
47 }
48 
49 int Lucas(ll n, ll k) {
50     if (!n && !k)    return 1;
51     return Lucas(n / p, k / p) * C[n % p][k % p] % p;
52 }
53 
54 int S(ll n, ll k) {
55     if (k < 0)    return 0;
56     return (pow2[n % p] * S(n / p, k / p - 1) + Lucas(n / p, k / p) * sc[n % p][k % p]) % p;
57 }
58 
59 inline void solve() {
60     printf("%d
", S(n, k));
61 }
62 
63 int T;
64 int main() {
65     prepare();
66     scanf("%d", &T);
67     while (T--) {
68         init();
69         solve();
70     }
71     return 0;
72 }
原文地址:https://www.cnblogs.com/yyf0309/p/8481803.html