2023杭电暑假多校8 题解 3 5 7 10 | JorbanS

3-Congruences

题意 m m m 组同余方程组 x p i ≡ q i ( m o d n ) , i ∈ [ 1 , m ] x^{p_i} \equiv q_i\pmod n,i\in[1,m] xpiqi(modn),i[1,m] n = ∏ i = 1 m p i n=\prod_{i=1}^m p_i n=i=1mpi,其中 p i p_i pi 两两互质,求所有满足条件的 x x x

题解 若有 x p ≡ q ( m o d n ) x^p\equiv q\pmod n xpq(modn) x p − q ≡ 0 ( m o d n ) x^p-q\equiv0\pmod n xpq0(modn),则 n ∣ x p − q n|x^p-q nxpq

p ∣ n p|n pn,则 p ∣ x p − q p|x^p-q pxpq,从而 x p ≡ q ( m o d p ) x^p\equiv q \pmod p xpq(modp)

根据费马小定理 x p − 1 ≡ 1 ( m o d p ) x^{p-1}\equiv 1\pmod p xp11(modp) x p ≡ x ( m o d p ) x^p\equiv x\pmod p xpx(modp),则 x ≡ q ( m o d p ) x\equiv q\pmod p xq(modp)

转化为了线性同余方程组,接下来直接利用 C R T CRT CRT 求解即可

上述推理过程可以简化为 x p ≡ q ( m o d n ) ⇒ x p ≡ q ( m o d p ) ⇔ x ≡ q ( m o d p ) ( ∗ 式 ) x^p\equiv q\pmod n\Rightarrow x^p\equiv q \pmod p \Leftrightarrow x\equiv q\pmod p(*式) xpq(modn)xpq(modp)xq(modp)()

在有解的情况下,求出 r r r,并特判 r = 0 r=0 r=0 的情况,即可得到最小正整数解。

( ∗ 式 ) (*式) () 第一步两边不互为充要条件,所以 C R T CRT CRT 求出的解不一定是原方程的解,需要验证解是否满足原方程。由于原方程对 n n n 取模,因此只需验证 r r r 一个数即可

#include <iostream>
#include <vector>
#define FastIO cin.tie(nullptr) -> sync_with_stdio(false);
#define Cases int __; cin >> __; for (int _ = 1; _ <= __; _ ++)
using namespace std;

#define lll __int128
typedef long long ll;

inline ll qpow(lll a, ll b, ll p) {
    lll res = 1;
    while (b) {
        if (b & 1) (res *= a) %= p;
        (a *= a) %= p;
        b >>= 1;
    }
    return res;
}

inline ll inv(ll x, ll p) { return qpow(x % p, p - 2, p); }

ll CRT(vector<ll> b, vector<ll> m, ll n) {
    ll res = 0;
    for (int i = 0; i < b.size(); i ++) {
        ll r = n / m[i];
        res += (lll)r * b[i] * inv(r, m[i]) % n;
    }
    return res % n;
}

ll solve() {
    int m; cin >> m;
    vector<ll> a, b, c;
    ll n = 1;
    for (int i = 0; i < m; i ++) {
        ll x, y; cin >> x >> y;
        a.push_back(x);
        b.push_back(y % x);
        c.push_back(y);
        n *= x;
    }
    ll res = CRT(b, a, n);
    for (int i = 0; i < m; i ++)
        if (qpow(res, a[i], n) != c[i])
            return -1;
    if (!res) return n;
    return res;
}

int main() {
    FastIO
    Cases
    cout << solve() << endl;
    return 0;
}

5-0 vs 1

题意 长度为 n n n 01 01 01 串, z e r o zero zero 只能取 0 0 0 o n e one one 只能取 1 1 1,每次只能从序列的左右两端取,不能取则对方获胜,若全部取完则平局输出 − 1 -1 1

题解 若当前轮到 z e r o zero zero:(轮到 o n e one one 同理)

  • 若左右两端都是 1 1 1,则对方即 o n e one one 获胜,输出 1 1 1
  • 若左右两端不一致,则选择 0 0 0 的那端,接下来轮到 1 1 1
  • 若左右两端都是 0 0 0,则此时 z e r o zero zero 掌握了主动权,因为无论 z e r o zero zero 选择哪边接下来 o n e one one 只能跟着选择同一边,同时易发现,能决定胜负的方式只有一端有两个 0 0 0 来使得对方落败,
  • 则贪心选择哪侧离下一个 0 0 0 更近(可以作预处理)使得自己获得主动权, e . g .   01...00 e.g.~01...00 e.g. 01...00 中选择右端的 0 0 0 010...110 010...110 010...110 选择左端的 1 1 1
#include <iostream>
#include <queue>
#include <bitset>
using namespace std;
#define FastIO cin.tie(nullptr) -> sync_with_stdio(false);
#define Cases int __; cin >> __; for (int _ = 1; _ <= __; _ ++)
#define endl '\n'

const int N = 1e5 + 2;
int l[2][N], r[2][N], last[2];
// l/r 存放 i 左/右边第一个 0/1 的下标
bitset<N> b;

int solve() {
    int n; cin >> n >> b;
    deque<int> dq;
    for (int i = 0; i < n; i ++) {
        bool t = b[i]; // 当前类型
        last[t] = l[t][last[t]] = i;
    }
    for (int i = n - 1; i >= 0; i --) {
        bool t = b[i];
        last[t] = r[t][last[t]] = i;
    }
    for (int i = 0; i < n; i ++) dq.push_back(i);
    bool t = 0; // 当前轮到谁
    while (!dq.empty()) {
        int left = dq.front(), right = dq.back();
        if (b[left] == t && b[right] == t)
            if (l[t][left] - left <= right - r[t][right]) dq.pop_front();
            else dq.pop_back();
        else if (b[left] != b[right])
            if (b[left] == t) dq.pop_front();
            else dq.pop_back();
        else return !t;
        t = !t;
    }
    return -1;
}

int main() {
    FastIO
    Cases
    cout << solve() << endl;
    return 0;
}

7-Solubility

题意 每次给定两种液体相融,液体相融具有结合律,最后问 k k k 种液体是否能全部相融

Tag 并查集

#include <iostream>
using namespace std;
#define FastIO cin.tie(nullptr) -> sync_with_stdio(false);
#define Cases int __; cin >> __; for (int _ = 1; _ <= __; _ ++)
#define endl '\n'
const string yes = "YES";
const string no = "NO";

const int N = 1e5 + 2;
int n, m, k, p[N];

inline int find(int x) { return x == p[x] ? x : p[x] = find(p[x]); }

string solve() {
    cin >> n >> m;
    for (int i = 1; i <= n; i ++) p[i] = i;
    while (m --) {
        int a, b; cin >> a >> b;
        p[find(a)] = p[find(b)];
    }
    cin >> k;
    k --;
    int last; cin >> last;
    bool flag = true;
    while (k --) {
        int x; cin >> x;
        if (p[find(x)] != p[find(last)]) flag = false;
        last = x;
    }
    if (flag) return yes;
    return no;
}

int main() {
    FastIO
    Cases
    cout << solve() << endl;
    return 0;
}

10-Rikka with Square Numbers

题意 a a a 变成 b b b,每次可以加或减去一个完全平方数

题解 n = ∣ a − b ∣ n=|a-b| n=ab,则只要计算加减完全平方数得到 n n n 的最少步骤

i i i1234567891011
i 2 i^2 i2149162536496481100121
i 2 − ( i − 1 ) 2 i^2-(i-1)^2 i2(i1)2N/A3579111315171921
i 2 − ( i − 2 ) 2 i^2-(i-2)^2 i2(i2)2N/AN/A81216202428323640

n n n 为完全平方数时,只需要一步操作

因为通过 i 2 − ( i − 1 ) 2 i^2-(i-1)^2 i2(i1)2 即两部操作得到所有大于 1 1 1 的奇数,减去 1 1 1 即可得到所有偶数,最坏也只需要 3 3 3

其次考虑 i 2 − ( i − 2 ) 2 i^2-(i-2)^2 i2(i2)2 即两部操作得到所有大于 4 4 4 4 4 4 的倍数

#include <iostream>
#include <cmath>
using namespace std;
#define FastIO cin.tie(nullptr) -> sync_with_stdio(false);
#define Cases int __; cin >> __; for (int _ = 1; _ <= __; _ ++)
#define endl '\n'
#define check(x) pow((int)sqrt(x), 2) == x

int solve() {
    int a, b; cin >> a >> b;
    int n = abs(a - b);
    if (check(n)) return 1;
    for (int i = 1; i * i <= n / 2; i ++)
        if (check(n - i * i))
            return 2;
    if ((n & 1) || n % 4 == 0) return 2;
    return 3;
}

int main() {
    FastIO
    Cases
    cout << solve() << endl;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JorbanS

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值