题目在这里
A.手动打表找规律得组合数
n -= 2, m -= 2, ans = C(n, m)
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int Mod = 1e9 + 7; ll fac[200010]; ll calc(ll x, int k = Mod - 2) { ll ret = 1; for(;k;k >>= 1, x = x * x % Mod) if(k & 1) ret = ret * x % Mod; return ret; } int main() { ios::sync_with_stdio(false); int n, m; fac[0] = fac[1] = 1; for(int i = 2;i <= 200000;i ++) fac[i] = fac[i - 1] * i % Mod; while(cin >> n >> m) { if(n > m) swap(n, m); cout << fac[m + n - 4] * calc(fac[n - 2]) % Mod * calc(fac[m - 2]) % Mod << endl; } return 0; }
B.
C.裸快速幂
#include <cstdio> using namespace std; double x = 1.000000011; double n; long long k; int main() { scanf("%lf %lld", &n, &k); for(;k;k >>= 1, x = x * x) if(k & 1) n = n * x; printf("%.8f ", n); return 0; }
D.递推式那么明显当然是矩阵快速幂啦
唯一需要注意的是,自乘矩阵的填充方式...
开始时,a1 对应 f(d) , a2 对应 f(d - 1) ...
#include <bits/stdc++.h> using namespace std; typedef long long ll; int d, n, m; struct matrix1{ ll c[15][15]; matrix1() { memset(c, 0, sizeof c); } void init() { memset(c, 0, sizeof c); for(int i = 0;i < d;i ++) cin >> c[d - 1 - i][d - 1], c[d - 1 - i][d - 1] %= m; for(int i = 1;i < d;i ++) c[i][i - 1] = 1; } matrix1 operator *(const matrix1 &a) const { matrix1 ret; for(int k = 0;k < d;k ++) for(int i = 0;i < d;i ++) if(c[i][k]) for(int j = 0;j < d;j ++) ret.c[i][j] = (ret.c[i][j] + c[i][k] * a.c[k][j]) % m; return ret; } }; struct matrix2{ ll c[15]; matrix2() { memset(c, 0, sizeof c); } void init() { memset(c, 0, sizeof c); for(int i = 0;i < d;i ++) cin >> c[i], c[i] %= m; } matrix2 operator *(const matrix1 &a) const { matrix2 ret; for(int i = 0;i < d;i ++) for(int j = 0;j < d;j ++) ret.c[i] = (ret.c[i] + c[j] * a.c[j][i]) % m; return ret; } }; int main() { matrix1 c1; matrix2 c2; while(cin >> d >> n >> m, d != 0) { c1.init(), c2.init(); for(n --;n;n >>= 1, c1 = c1 * c1) if(n & 1) c2 = c2 * c1; cout << c2.c[0] << endl; } return 0; }
E.参考 CodeForces - 785D
F.看样例猜结论就好了
输出所有质数的幂就好了
#include <iostream> using std::cin; using std::endl; using std::cout; int n, v[1011], p[1011]; int main() { cin >> n; for(int i = 2;i <= n;i ++) { if(!v[i]) { for(int j = i;j <= n;j *= i) p[++ p[0]] = j; } for(int j = i << 1;j <= n;j += i) v[j] = 1; } cout << p[0] << endl; for(int i = 1;i <= p[0];i ++) cout << p[i] << " "; return 0; }
G.参考 CodeForces - 785C
H.
I.能被 6 整除一定能被 2 和 3 整除,8 和 9 同理
于是就是求 1 - n 内2 3 5 7的倍数之和
容斥原理即可
#include <iostream> using namespace std; int main() { long long n; cin >> n; cout << n - n / 2 - n / 3 - n / 5 - n / 7 + n / 6 + n / 10 + n / 14 + n / 35 + n / 21 + n / 15 - n / 105 - n / 70 - n / 42 - n / 30 + n / 210; return 0; }
J.
K.对于n 的每一个因数 t
它对答案贡献为 t * phi(n / t)
效率玄学吧
#include <cstdio> int v[60000], p[60000]; int phi(int x) { int ret = x; for(int i = 1;1ll * p[i] * p[i] <= x;i ++) if(x % p[i] == 0) { ret = ret - ret / p[i]; while(x % p[i] == 0) x /= p[i]; } if(x != 1) ret -= ret / x; return ret; } int main() { long long n, ans; for(int i = 2;i < 60000;i ++) { if(!v[i]) p[++ p[0]] = i; for(int j = 1;j <= p[0] && p[j] * i < 60000;j ++) { v[p[j] * i] = 1; if(i % p[j] == 0) break; } } while(scanf("%lld", &n) != EOF) { ans = 0; for(long long i = 1;i * i <= n;i ++) { if(n % i) continue; ans += i * phi(n / i); if(i * i != n) ans += n / i * phi(i); } printf("%lld ", ans); } return 0; }
L.和式加一项减一项变成了C(n + m, n)
n,m 大 p 小且 p 保证为质数,使用卢卡斯定理
Lucas(n,m) % p = Lucas(n / p,m / p) * Comb(n % p,m % p) % p
注意lucas里面的取模后计算组合数,可能会出现 C(n,m) 里 n < m
所以Comb函数里需要判断的
考虑 p 为读入的不能预处理,所以我们有两种解决方案
1.每组数据 O(p) 预处理处阶乘 fac
Comb就可以 O(logn) 回答,理论效率 O(p + logn * log(p)(n + m))
大概就是 O(p)
#include <bits/stdc++.h> using namespace std; typedef long long ll; int t, n, m, p; ll fac[100010]; ll calc(ll x, int k = p - 2) { ll ret = 1; for(;k;k >>= 1, x = x * x % p) if(k & 1) ret = ret * x % p; return ret; } ll C(int n, int m) { if(n < m) return 0; return fac[n] * calc(fac[m]) % p * calc(fac[n - m]) % p; } ll lucas(int n, int m) { if(!m) return 1; return C(n % p, m % p) * lucas(n / p, m / p) % p; } int main() { ios::sync_with_stdio(false); fac[0] = 1; cin >> t; while(t --) { cin >> n >> m >> p; for(int i = 1;i < p;i ++) fac[i] = fac[i - 1] * i % p; cout << lucas(n + m, n) << endl; } return 0; }
2.不进行预处理,Comb直接 O(p + logn) 回答
理论效率O(p * log(p)(n + m))
#include <bits/stdc++.h> using namespace std; typedef long long ll; int t, n, m, p; ll calc(ll x, int k = p - 2) { ll ret = 1; for(;k;k >>= 1, x = x * x % p) if(k & 1) ret = ret * x % p; return ret; } ll C(int n, int m) { if(n < m) return 0; ll ret1 = 1, ret2 = 1; for(int i = 1, j = n;i <= m;i ++, j --) { ret1 = ret1 * i % p; ret2 = ret2 * j % p; } return ret2 * calc(ret1) % p; } ll lucas(int n, int m) { if(!m) return 1; return C(n % p, m % p) * lucas(n / p, m / p) % p; } int main() { ios::sync_with_stdio(false); cin >> t; while(t --) { cin >> n >> m >> p; cout << lucas(n + m, n) << endl; } return 0; }
然而第二种的表现更好...因为都是最坏时间估计
而第一种稳定在O(p),第二种实际是几倍优于最坏效率的
M.