2025十一集训——Day2做题
https://vjudge.net/contest/753101
A.
给 a、b、d,求 x 使 \(a or x\) 与 \(b or x\) 是 d 的因数,\(a,b,d<2^{30}\),要求 \(x<2^{60}\)
考虑让 \(a or x = x\),\(b or x = x\),使 x 是 d 的倍数即可。
首先让 d 为奇数,直接右移 lowbit(d),同时 a、b 也要右移 lowbit d,但是如果 lowbit(a(或b)) < lowbit(d) 就无解(因为是或,这个1一定去不掉)。
所以 \(a or b\) 的每一个 1 的位 x 也为 1。所以拆位,如果 \(a or b\) 的该位为 1,但是我们当前的答案这位为 0,就把答案加上 \(d*2^i\),由于 \(a,b,d<2^{30}\),所以答案必定在范围内。
代码:
点击查看代码
#include <bits/stdc++.h>
#define dbg(x) cout << #x << '=' << x << endl
#define rep(i, l, r) for (int i = (l); i <= (r); i++)
#define frep(i, r, l) for (int i = (r); i >= (l); i--)
#define int long long
using namespace std;
void work()
{
int a, b, d; cin >> a >> b >> d;
int num = 0; a |= b;
while (!(d & 1)) num++, d >>= 1;
if (a & ((1 << num) - 1)) {
cout << "-1\n"; return ;
}
a >>= num;
int k = 0;
for (int i = 0; i <= 30; i++) {
if (a & (1 << i) && !(k & (1 << i)))
k += d << i;
}
cout << (k << num) << "\n";
}
signed main()
{
std::ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int T = 1, opinput = 1;
if (opinput) cin >> T;
while (T--) work();
return 0;
}
B
题意,一个集合,元素 \(<=n\),若 \(x\),\(y\) 在集合内 \((x+y)mod n\) 也在集合,现在知道 \(k-1\) 个不在集合的数和一个在集合的数,求集合最多多少元素。
若 \(x\) 在集合,易证 \(kx\) 在集合,所以转换成一个同余类问题,求出最小的在集合的 \(x\) 便可以求出集合大小最大值,显然同时为 \(n\) 和 \(m_k\) 的因数满足性质。所以求出 \(\gcd(n,m_k)\),一个暴力的思路是枚举他的所有因子,然后check是不是不合法数的因数,显然不对(其实原来数据水能过,但加强了,被卡在76分┭┮﹏┭┮),然后强一点,首先把 \(m_i\) 变成 \(\gcd(m_i,n)\),限制显然不会更劣,先筛出 \(\gcd(n,m_k)\) 的质因子和因子,然后对于每一个 \(m_i\) 不断递归除掉这些质因子,如果有 \(\gcd(n,m_k)\) 就标记掉,显然质因子是 \(log\) 级的,而因子是 \(\sqrt(n)\) 这些预处理显然不会超时(懒得分析复杂度……)。
然后在没被筛掉的因子中找个最小的即可……
点击查看代码
#include <bits/stdc++.h>
#define int long long
#define dbg(x) cout << #x << '=' << x << endl
#define rep(i, l, r) for (int i = (l); i <= (r); i++)
#define frep(i, r, l) for (int i = (r); i >= (l); i--)
using namespace std;
const int N = 250001;
int n;
int k;
int a[N];
int read()
{
int f = 1, s = 0; char ch = getchar();
while (ch < '0' || ch > '9') {if (ch == '-') f = -1; ch = getchar();}
while (ch >= '0' && ch <= '9') {s = s * 10 + ch - '0'; ch = getchar();}
return f * s;
}
int Gcd(int a, int b) {return b ? Gcd(b, a % b) : a;}
bool Check(int x) {
rep(i, 1, k) {
if (a[i] % x == 0) return 0;
}
return 1;
}
unordered_map<int, bool>mp;
vector<int> p;
void Dfs(int x) {
if (!mp[x]) return;
mp[x] = 0;
for (int num : p) {
if (x % num == 0) Dfs(x / num);
}
}
signed main()
{
scanf("%lld%d", &n, &k);
k--;
rep(i, 1, k) scanf("%lld", a + i);
int x; scanf("%lld", &x);
x = Gcd(x, n);
int ans = 0;
int y = x;
for (int i = 2; i * i <= y; i++) {
if (y % i) continue;
p.push_back(i);
while (y % i == 0) y /= i;
}
if (y > 1) p.push_back(y);
for (int i = 1; i * i <= x; i++) {
if (x % i) continue;
mp[i] = mp[x / i] = 1;
// cout << i << " " << x / i << "\n";
}
rep(i, 1, k) Dfs(Gcd(a[i], x));
for (int i = 1; i * i <= x; i++) {
if (x % i) continue;
if (mp[i]) {
cout << n / i; return 0;
}
if (mp[x / i]) {
ans = n / (x / i);
}
}
printf("%lld\n", ans);
return 0;
}
C
中国剩余定理板子
一个板子……就不写题解了,感觉很好理解……
挂个代码:
点击查看代码
#include <bits/stdc++.h>
#define dbg(x) cout << #x << '=' << x << endl
#define rep(i, l, r) for (int i = (l); i <= (r); i++)
#define frep(i, r, l) for (int i = (r); i >= (l); i--)
#define int __int128
using namespace std;
const int N = 15;
int n;
int a[N], b[N];
void Exgcd(int a, int b, int &x, int &y) {
if (a == 1 && b == 0) {x = 1, y = 0; return;}
Exgcd(b, a % b, y, x);
y -= a / b * x;
}
int read()
{
int f = 1, s = 0; char ch = getchar();
while (ch < '0' || ch > '9') {if (ch == '-') f = -1; ch = getchar();}
while (ch >= '0' && ch <= '9') {s = s * 10 + ch - '0'; ch = getchar();}
return f * s;
}
void write(int x) {
if (x > 9) write(x / 10);
putchar(x % 10 + '0');
}
signed main()
{
std::ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
n = read();
int res = 1, ans = 0;
rep(i, 1, n)
a[i] = read(), b[i] = read(), res *= a[i];
rep(i, 1, n) {
int k = res / a[i];
int x, y;
Exgcd(k, a[i], x, y);
ans = (ans + k * b[i] * x % res) % res;
}
ans = (ans % res + res) % res;
write(ans);
return 0;
}
D
题意:求 \(g^{\sum_{d|n}C_n^d} mod 999911659\)
数论全家桶……
g^x快速幂。
用欧拉定理质数模上 999911658,
求 \sum_{d|n} 直接枚举因子。
C 这个考虑将模数缩小用 Lucas。
将 999911658 质因数分解,用 lucas 算出四个\sum_{d|n}C_n^d,相当于四个同余方程呀!直接 CRT 合并即可。
好题。好题。
点击查看代码
#include <bits/stdc++.h>
#define dbg(x) cout << #x << '=' << x << endl
#define rep(i, l, r) for (int i = (l); i <= (r); i++)
#define frep(i, r, l) for (int i = (r); i >= (l); i--)
#define int long long
using namespace std;
const int Mod = 999911659;
const int mod = 999911658;
const int N = 5;
const int M = 5e4 + 10;
int n, g;
int Qpow(int a, int b, int p) {
int res = 1;
while (b) {
if (b & 1) res = (res * a) % p;
a = a * a % p; b >>= 1;
}
return res;
}
int Inv(int x, int p) {
return Qpow(x, p - 2, p);
}
int fac[M], inf[M];
void Init(int p) {
fac[0] = inf[0] = 1;
rep(i, 1, p) fac[i] = fac[i - 1] * i % p;
rep(i, 1, p) inf[i] = Inv(fac[i], p);
}
int C(int n, int m, int p) {
if (n < m) return 0;
return fac[n] * inf[m] % p * inf[n - m] % p;
}
int Lucas(int n, int m, int p) {
if (n < m) return 0;
if (n == 0) return 1;
return C(n % p, m % p, p) * Lucas(n / p, m / p, p) % p;
}
int cnt, pri[N];
int a[N];
void Cut(int x) {
int now = 2;
while (now * now < x) {
if (x % now == 0)
pri[++cnt] = now, x /= now;
now++;
}
if (x != 1) pri[++cnt] = x;
}
int CRT() {
int res = 0;
rep(i, 1, cnt) {
res = (res + a[i] * (mod / pri[i]) % mod * Inv(mod / pri[i], pri[i])) % mod;
}
return res;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
cin >> n >> g;
if (g % Mod == 0) {
cout << 0 << "\n";
return 0;
}
Cut(mod);
rep(i, 1, cnt) {
int p = pri[i];
Init(p);
for (int j = 1; j * j <= n; j++) {
if (n % j) continue;
a[i] = (a[i] + Lucas(n, j, p)) % p;
if (n / j != j)
a[i] = (a[i] + Lucas(n, n / j, p)) % p;
}
}
// rep(i, 1, n) cout << a[i] << " ";
int ans = CRT();
cout << Qpow(g, ans, Mod) << "\n";
return 0;
}
E
模数不互质,和 CRT 没有半毛钱关系。
简单推导,本质思想是合并两个方程,更使用一点,而且不难写。
挂个式子:
显然是个扩欧,判 \(\gcd(b_i, b_j) | (a_i-a_j)\)。
若有解:
设特解为:\(x_0,y_0\)
通解为:$$X=x_0+\frac{b_i}{\gcd(b_i,b_j)}×k, Y=y_0-\frac{b_j}{\gcd(b_i,b_j)}×k$$
把这个代回 \(x=k_jb_j+a_j\)
所以合并后的方程 \(x=A(mod B)\) 即有:$$A=x_0b_i+b_j,B=lcm(b_i,b_j)$$
OK了!
点击查看代码
#include <bits/stdc++.h>
#define dbg(x) cout << #x << '=' << x << endl
#define rep(i, l, r) for (int i = (l); i <= (r); i++)
#define frep(i, r, l) for (int i = (r); i >= (l); i--)
#define int __int128
using namespace std;
const int N = 1e5 + 10;
int n, a[N], b[N];
int Gcd(int a, int b) {return b ? Gcd(b, a % b) : a;}
int read()
{
int f = 1, s = 0; char ch = getchar();
while (ch < '0' || ch > '9') {if (ch == '-') f = -1; ch = getchar();}
while (ch >= '0' && ch <= '9') {s = s * 10 + ch - '0'; ch = getchar();}
return f * s;
}
void write(int x) {
if (x > 9) write(x / 10);
putchar(x % 10 + '0');
}
void Exgcd(int a, int b, int &x, int &y) {
if (b == 0) {x = 1, y = 0; return;}
Exgcd(b, a % b, y, x);
y -= a / b * x;
}
signed main()
{
std::ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
n = read();
rep(i, 1, n) a[i] = read(), b[i] = read();
int A = a[1], B = b[1];
rep(i, 2, n) {
int p, q;
int d = Gcd(A, a[i]);
Exgcd(A, a[i], p, q);
p = p * (b[i] - B) / d;
p = (p % (a[i] / d) + (a[i] / d)) % (a[i] / d);
B = A * p + B;
A = A / d * a[i];
}
write((B % A + A) % A);
return 0;
}
F
咕咕咕
G
扩展lucas板子(\(C_m^n (mod p)\))
思想类似于古代猪文那题,先把模数质因数分解,分别求出然后CRT合并。所以求 \(C_m^n (mod p^k)\)
这东西恶心在于模数不是质数,不能保证有逆元,需要转化。
具体推导有点复杂,大概思想是对于 \(n!(mod p^k)\),把 \(p\) 的倍数都拿出来,大概是 \(1×2×...×n=(p×2p×3p×...)×(1×2×...×(p-1)×(p+1)×.....\),前面又等于 \(p(1×2×...)\),共有 \(n/p\)(无特殊说明为下取整) 个,所以是 \(p×(n/p)!\),后面那坨拆成一些循环节即可。
令 \(f(n)=n!/p^k\),则 \(f(n)=f(n/k)+(p-1)!^{n/k}+rest\) (rest为最后一段的积。)
然后再求一个 \(g(n)\) 表示 \(n!\) 里共有多少个 \(p\),方法同上 \(g(n)=g(n/p)+n/p\)。
开始搞事:
这样就OK了,\(f(n),g(n)\) 递归求解都是 \(O(log_p n)\) 的。
做完了……!
点击查看代码
#include <bits/stdc++.h>
#define int long long
#define dbg(x) cout << #x << '=' << x << endl
#define rep(i, l, r) for (int i = (l); i <= (r); i++)
#define frep(i, r, l) for (int i = (r); i >= (l); i--)
using namespace std;
const int N = 1e6 + 10;
int n, m, p;
int Qpow(int a, int b, int mod) {
a %= mod;
int res = 1;
while (b) {
if (b & 1) res = res * a % mod;
a = a * a % mod; b >>= 1;
}
return res;
}
void Exgcd(int a, int b, int &x, int &y) {
if (b == 0) {x = 1, y = 0; return;}
Exgcd(b, a % b, y, x);
y -= a / b * x;
}
int Inv(int a, int p) {
int x, y;
Exgcd(a, p, x, y);
return (x % p + p) % p;
}
int F(int n, int p, int pk) {
if (n == 0) return 1;
int num = 1, res = 1;
int cnt = n / pk;
rep(i, 1, pk) {
if (i % p) num = num * i % pk;
}
rep(i, cnt * pk, n) {
if (i % p) res = res * (i % pk) % pk;
}
return F(n / p, p, pk) * Qpow(num, cnt, pk) % pk * res % pk;
}
int G(int n, int p) {
if (n < p) return 0;
return G(n / p, p) + n / p;
}
int tot;
int a[N], b[N];
int C(int n, int m, int p, int pk) {
int fn = F(n, p, pk), fm = F(m, p, pk), fnm = F(n - m, p, pk);
int num = G(n, p) - G(m, p) - G(n - m, p);
return fn * Inv(fm, pk) % pk * Inv(fnm, pk) % pk * Qpow(p, num, pk) % pk;
}
void ExLucas(int p) {
int x = p;
for (int i = 2; i * i <= x; i++) {
if (x % i) continue;
int pk = 1;
while (x % i == 0)
x /= i, pk *= i;
tot++;
b[tot] = pk;
a[tot] = C(n, m, i, pk);
}
if (x > 1) {
tot++;
b[tot] = x;
a[tot] = C(n, m, x, x);
}
}
int Crt() {
int res = 0;
int x, y;
rep(i, 1, tot) {
// cout << a[i] << " " << b[i] << "\n";
int now = p / b[i];
res = (res + now * a[i] % p * Inv(now, b[i]) % p) % p;
}
return res;
}
signed main()
{
std::ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
cin >> n >> m >> p;
ExLucas(p);
cout << Crt() << "\n";
return 0;
}
本文来自博客园,作者:zhangxiao666,转载请注明原文链接:https://www.cnblogs.com/zhangxiao666qwq/p/19124953

浙公网安备 33010602011771号