动态规划
思路
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| #include <iostream> #include <cstring> #include <algorithm>
using namespace std;
const int N = 2010,M = 1e9 + 7;
int C[N][N];
int n; int a,b;
int main() { for(int i = 0; i < N; ++ i) for(int j = 0; j <= i; ++ j) if(!j) C[i][j] = 1; else C[i][j] = (C[i-1][j] + C[i-1][j-1]) % M; cin >> n; while(n--) { cin >> a >> b; cout << C[a][b] << endl; } return 0; }
|
乘法逆元
乘法逆元
如果 $b$ 与 $p$ 互质,且对于任意整数 $a$,如果 $b|a$,则存在一个整数 $x$,$\frac{a}{b} \equiv {a \times x} \pmod p$, $x$ 称为 $b$ 的模 $p$ 逆元。
$b$ 存在乘法逆元的充要条件是 $b$ 与模数 $p$ 互质。当模数 $p$ 为质数时,$b^{p−2}$ 即为 $b$ 的乘法逆元。
思路
预处理出所有数据范围内的阶乘及其逆元,根据$C_a^b=\frac{a!}{b! \times (a - b)!}$。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| #include <iostream> #include <cstring> #include <algorithm>
using namespace std;
typedef long long LL;
const int N = 1e5 + 10,M = 1e9 + 7;
int n,a,b;
int fact[N],infact[N];
int qmi(int a,int b,int p) { int res = 1 % p; while(b) { if(b&1) res = (LL)res * a % p; a = (LL)a * a % p; b >>= 1; } return res; }
int main() { fact[0] = infact[0] = 1; for(int i = 1; i < N; ++ i){ fact[i] = (LL)fact[i-1] * i % M; infact[i] = (LL)infact[i-1] * qmi(i,M - 2,M) % M; } scanf("%d", &n); while(n--) { scanf("%d%d",&a,&b); int res = (LL)fact[a] * infact[b] % M * infact[a-b] % M; printf("%d\n",res); } return 0; }
|
Lucas定理
思路
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| #include <iostream> #include <cstring> #include <algorithm>
using namespace std;
typedef long long LL;
const int N = 1e5 + 10;
int n; LL a,b; int p;
int qmi(LL a,LL b,int p) { int res = 1; while(b) { if(b & 1) res = (LL)res * a % p; a = (LL)a * a % p; b >>= 1; } return res; }
int C(LL a,LL b,int p) { int res = 1 % p; for(int i = 1, j = a; i <= b; ++ i, -- j) { res = (LL)res * j % p; res = (LL)res * qmi(i,p - 2,p) % p; } return res; }
int lucas(LL a,LL b,int p) { if(a < p) return C(a,b,p); int res = 1; res = (LL)C(a % p,b % p, p) * lucas(a / p,b / p,p) % p; return res; }
int main() { scanf("%d", &n); while(n--) { scanf("%lld%lld%d",&a,&b,&p); printf("%d\n",lucas(a,b,p)); } return 0; }
|
高精度
思路
根据算术基本定理,把三个数分解成若干质数乘积,然后约分,最后只剩高精度乘法运算。
如何求 $a$ 中包含多少个 $p$?
算出一个$p$的个数,然后是$p^2$的个数,$p^2$包含两个$p$,但是由于$p^2$中的一个$p$已经加上了,故只需加一次,以此类推。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
| #include <iostream> #include <cstring> #include <algorithm> #include <vector> #include <unordered_map>
using namespace std;
const int N = 5010;
int a,b; int primes[N]; bool st[N]; int cnt; int sum[N];
vector<int> mul(vector<int> &a,int b) { vector<int> c; int t = 0; for(int i = 0; i < a.size(); ++ i) { t += a[i] * b; c.push_back(t % 10); t /= 10; } while(t) { c.push_back(t % 10); t /= 10; } return c; }
void get_primes(int n) { for(int i = 2; i <= n; ++ i) { if(!st[i]) primes[cnt ++] = i; for(int j = 0; primes[j] <= n / i; ++ j) { st[primes[j] * i] = true; if(i % primes[j] == 0) break; } } }
int get(int x,int p) { int res = 0; while(x) { res += x / p; x /= p; } return res; }
int main() { cin >> a >> b; get_primes(a); for(int i = 0; i < cnt; ++ i) sum[i] = get(a,primes[i]) - get(b,primes[i]) - get(a - b,primes[i]); vector<int> res; res.push_back(1); for(int i = 0 ; i < cnt; ++ i) for(int j = 0; j < sum[i]; ++ j) res = mul(res,primes[i]); for(int i = res.size() - 1; i >= 0; -- i) printf("%d",res[i]); return 0; }
|