2025十一集训——Day2做题

https://vjudge.net/contest/753101

A.

vjudge

CF

给 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

vjudge

洛谷

题意,一个集合,元素 \(<=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

中国剩余定理板子

vjudge

洛谷

一个板子……就不写题解了,感觉很好理解……

挂个代码:

点击查看代码
#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

vjudge

洛谷

题意:求 \(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

vjudge

洛谷

模数不互质,和 CRT 没有半毛钱关系。

简单推导,本质思想是合并两个方程,更使用一点,而且不难写。

挂个式子:

\[x=a_i(mod b_i),x=a_j(mod b_j) \]

\[x=k_ib_i+a_i=k_jb_j+a_j \]

\[k_i b_i - k_j b_j = a_i-a_j \]

显然是个扩欧,判 \(\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=(x_0+\frac{b_i}{\gcd(b_i,b_j)}×k)×b_j+a_j=x_0b_i+lcm(b_i,b_j)k+b_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

vjudge

洛谷

扩展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\)

开始搞事:

\[C_m^n(mod p^k) \]

\[=\frac{n!}{m!(n-m)!}(mod p^k) \]

\[=\frac{\frac{n!}{p^x}}{\frac{m!}{p^y}\frac{(n-m)!}{p^z}}p^{x-y-z}(mod p^k) \]

\[=\frac{f(n)}{f(m)f(n-m)!}p^{g(n)-g(m)-g(n-m)}(mod p^k) \]

这样就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;
}
posted @ 2025-10-03 20:19  zhangxiao666  阅读(8)  评论(0)    收藏  举报