三道题都是比较裸的题,主要是记录一下板子。
Strange Way to Express Integers
非常裸的EXCRT,注意一些小细节。
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
const int maxn = 1e5 + 5;
typedef long long ll;
ll a[maxn], m[maxn];
ll x, i, j, d, M;
ll gcd(ll a, ll b) {
if (b == 0) return a;
if (b == 1) return 1;
return gcd(b, a % b);
}
ll lcm(ll a, ll b) {
return a * b / gcd(a, b);
}
ll exgcd(ll a, ll b, ll &x, ll &y) {
if (b == 0) { x = 1; y = 0; return a; }
ll d = exgcd(b, a % b, x, y);
ll k = x;
x = y, y = k - y * (a / b);
return d;
}
int main() {
int n;
while (~scanf("%d", &n)) {
for (int s = 1; s <= n; s++) scanf("%lld %lld", &m[s], &a[s]);
M = m[1];
x = a[1];
ll d;
int flag = 1;
for (int s = 2; s <= n; s++) {
d = exgcd(M, m[s], i, j);
if ((a[s] - x) % d) {
printf("-1
");
flag = 0;
break;
}
i = i * ((a[s] - x) / d);
//将i调整到合适的范围
i = (i % m[s] + m[s]) % m[s];
//这里不要对x取模,否则会挂的很惨
x = x + i * M;
M = lcm(M, m[s]);
}
if (flag) printf("%lld
", x % M);
}
return 0;
}
古代猪文
欧拉定理内容
如果 (gcd(a,p) = 1),那么 (a^{varphi(p)} equiv 1 pmod{p})
扩展
在模(p)意义下
- (a^b equiv a^{b mod varphi(p)}),(gcd(a,p) = 1)
- (a^b equiv a^{(b mod varphi(p))+varphi(p)}),(gcd(a,p) e 1, varphi(p) leq b)
然后看这道题,题意是求 (g^{sum_{k|n}{n choose k}} mod 999911659)
直接做显然会指数爆炸,然后考虑用扩展欧拉定理对指数取模,发现999911659是素数,于是原式变为 (g^{sum_{k|n}{n choose k} mod 999911658} mod 999911659)
问题转化为求 (sum_{k|n}{n choose k} mod 999911658),发现999911658刚好能拆成4个素数因子相乘,可以用lucas+crt解决,否则就要像下面的礼物一样用exlucas了。
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <iostream>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 5;
ll a[5];
ll jc[maxn];
ll Qpow(ll x, ll t, ll p) {
x %= p;
ll s = 1;
while (t) {
if (t & 1) s = s * x % p;
x = x * x % p;
t >>= 1;
}
return s;
}
ll C(ll n, ll m, ll p) {
if (n < m) return 0;
if (m == 0) return 1;
return jc[n] * Qpow(jc[m], p - 2, p) % p * Qpow(jc[n - m], p - 2, p) % p;
}
ll Lucas(ll n, ll m, ll p) {
if (m == 0) return 1;
return C(n % p, m % p, p) * Lucas(n / p, m / p, p) % p;
}
ll n, g;
ll factor[maxn], p[5] = { 0, 2, 3, 4679, 35617 };
ll Crt() {
ll M = 1;
for (int i = 1; i <= 4; i++) M *= p[i];
ll ans = 0;
for (int i = 1; i <= 4; i++)
ans = (ans + a[i] * (M / p[i]) % M * Qpow(M / p[i], p[i] - 2, p[i]) % M) % M;
return ans;
}
int main() {
scanf("%lld %lld", &n, &g);
if (g % 999911659 == 0) return printf("0
"), 0;
for (int i = 1; i * i <= n; i++) {
if (n % i == 0) {
factor[++factor[0]] = i;
if (n / i != i) factor[++factor[0]] = n / i;
}
}
for (int i = 1; i <= 4; i++) {
jc[0] = 1;
for (int j = 1; j <= p[i]; j++) jc[j] = jc[j - 1] * j % p[i];
for (int j = 1; j <= factor[0]; j++)
a[i] = (a[i] + Lucas(n, factor[j], p[i])) % p[i];
}
ll x = Crt();
printf("%lld
", Qpow(g, x, 999911659));
return 0;
}
礼物
题意为
[prod_{i=1}^{n} {{n - sum_{j=1}^{i-1}w[j]} choose w[i]} mod p
]
问题在于 (p),不一定是质数,而且分解质因子后每个质因子的指数也不一定都是1,所以用exlucas求解每个分问题,注意求逆元因为模数不一定是质数不能用费马小定理,因为每个模数一定互质,最后crt合并即可。
附exlucas讲解:学exlucas这一篇就够了,吹爆Midoria7%%%
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <cmath>
using namespace std;
const int maxn = 20;
typedef long long ll;
void Ex_gcd(ll a, ll b, ll &x, ll &y) {
if (!b) { x = 1, y = 0; return; }
Ex_gcd(b, a % b, x, y);
ll z = x;
x = y, y = z - y * (a / b);
}
ll Inv(ll a, ll b) {
ll x, y;
Ex_gcd(a, b, x, y);
return (x % b + b) % b;
}
ll Qpow(ll x, ll t, ll mod) {
ll s = 1;
while (t) {
if (t & 1) s = s * x % mod;
x = x * x % mod;
t >>= 1;
}
return s;
}
ll Fac(ll n, ll p, ll pk) {
if (!n) return 1;
ll res = 1;
for (ll i = 1; i <= pk; i++) if (i % p) res = res * i % pk;
res = Qpow(res, n / pk, pk);
for (ll i = 1; i <= n % pk; i++) if (i % p) res = res * i % pk;
return res * Fac(n / p, p, pk) % pk;
}
ll C(ll n, ll m, ll p, ll pk) {
ll x = 0, y = 0, z = 0;
for (ll i = p; i <= n; i *= p) x += n / i;
for (ll i = p; i <= m; i *= p) y += m / i;
for (ll i = p; i <= n - m; i *= p) z += (n - m) / i;
return (Fac(n, p, pk) * Inv(Fac(m, p, pk), pk) % pk * Inv(Fac(n - m, p, pk), pk) % pk * Qpow(p, x - y - z, pk) % pk) % pk;
}
ll Crt(ll n, ll a[], ll mod[]) {
ll M = 1, res = 0;
for (int i = 1; i <= n; i++) M *= mod[i];
ll w, x, y;
for (int i = 1; i <= n; i++) {
w = M / mod[i];
res = (res + a[i] * Inv(w, mod[i]) * w % M) % M;
}
return res;
}
ll Ex_lucas(ll n, ll m, ll P) {
ll mod[20], a[20], cnt = 0;
for (ll i = 2; i * i <= P; i++) {
if (P % i == 0) {
mod[++cnt] = 1;
while (P % i == 0) {
mod[cnt] *= i;
P /= i;
}
a[cnt] = C(n, m, i, mod[cnt]);
}
}
if (P > 1) mod[++cnt] = P, a[cnt] = C(n, m, P, P);
return Crt(cnt, a, mod);
}
#define cnt pk[0]
ll ans[maxn], pk[maxn];
int main() {
ll n, m, p, w[10];
scanf("%lld %lld %lld", &p, &n, &m);
for (int i = 1; i <= m; i++) scanf("%lld", &w[i]);
for (ll i = 2; i * i <= p; i++) {
if (p % i == 0) {
pk[++cnt] = 1;
while (p % i == 0) {
pk[cnt] *= i;
p /= i;
}
}
}
if (p > 1) pk[++cnt] = p;
for (int i = 1; i <= cnt; i++) ans[i] = 1;
ll sum = 0;
for (int i = 1; i <= m; i++) sum += w[i];
if (sum > n) return printf("Impossible
"), 0;
sum = 0;
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= cnt; j++) {
ans[j] = (ans[j] * Ex_lucas(n - sum, w[i], pk[j]) % pk[j]) % pk[j];
}
sum += w[i];
}
printf("%lld
", Crt(cnt, ans, pk));
return 0;
}