2023杭电暑假多校6 题解 1 2 6 10 | JorbanS

1-Count

本题数据待增强,未设置 k = n k=n k=n 的数据

题意 求出多少满足 A i = A n − k + i , i ∈ [ 1 , k ) A_i=A_{n-k+i},i\in[1,k) Ai=Ank+i,i[1,k) 的长度为 n n n 的序列 A A A 有多少种,其中 A i ∈ [ 1 , m ] A_i\in[1,m] Ai[1,m],保证 k ≤ n k\le n kn

Tag 快速幂

[----]----[----]
1    k  n-k+1  n
     l    r

[------[--------]------]
1   n-k+1       k      n
       r        l

题解 即序列 A A A 的前缀和后缀相同有多少种情况,令左区间右端点 l = k l=k l=k,右区间左端点 r = n − k + 1 r=n-k+1 r=nk+1

  • l < r l<r l<r 时,区间 [ r , n ] = [ 1 , l ] [r,n]=[1,l] [r,n]=[1,l],区间 [ 1 , r ) [1,r) [1,r) 内的数任意取
  • l ≥ r l\ge r lr 时,区间 [ 1 , r ] [1,r] [1,r] 为周期循环,区间 [ 1 , r ) [1,r) [1,r) 内的数任意取

n = k n=k n=k 时,特判 r e s = m n res=m^n res=mn

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

typedef long long ll;
const int mod = 998244353;
ll n, m, k;

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

int main() {
    FastIO
    Cases
    {
        cin >> n >> m >> k;
        cout << qpow(m % mod, n - k) << endl;
    }
    return 0;
}

2-Pair Sum and Perfect Square

题意 给定 1 ∼ n 1\sim n 1n 的排列 p p p,询问区间 [ L , R ] [L,R] [L,R] 内有多少对 p i , p j , i ≠ j p_i,p_j,i\neq j pi,pj,i=j 使得 p i + p j p_i+p_j pi+pj 为完全平方数

Tag 扫描线 树状数组

题解 最多只有 199999 ≈ 447.2 \sqrt{199999}≈447.2 199999 447.2 个完全平方数,考虑将每对 p i + p j , i < j p_i+p_j,i<j pi+pj,i<j 是完全平方数的贡献置于 i i i 点,扫描线维护,扫到 x x x 时维护所有 i < j ≤ x i<j\le x i<jx i i i 的贡献,离线后用树状数组维护即可

单点相加的次数的最坏情况为 ∑ i = 1 199999 i ≈ ∫ 1 199999 x 1 2 d x ≈ 2 3 19999 9 3 2 ≈ 5.96 × 1 0 7 \sum \limits _{i=1}^{199999}\sqrt{i} \approx\int_{1}^{199999}x^{\frac{1}{2}}dx\approx\frac{2}{3}199999^{\frac{3}{2}}\approx5.96\times10^7 i=1199999i 1199999x21dx32199999235.96×107,由于杭电机子体质惊人,可以过

e , g . e,g. e,g. r r r 遍历到 1 1 1 时, 15 15 15 + 1 +1 +1;当 r r r 遍历到 6 6 6 时,会加上 r e s − q u e r y ( l − 1 ) res-query(l-1) resquery(l1),也会算上配对 ( 1 , 15 ) (1, 15) (1,15),就神奇的统计进去了 🥰🥰

----------->r扫描
9 2 15 10 1 6
    +1

以下是 c o d e code code

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

using namespace std;
typedef pair<int, int> pii;
const int N = 1e5 + 2, M = 450;
int n, sq[M], p[N], pos[N];

struct Fenwick {
    int tr[N << 1];
    
    inline int lowbit(int x) { return x & -x; }
    
    void clear() { memset(tr, 0, sizeof tr); }
    
    inline void add(int x, int k) {
        while (x <= n) {
            tr[x] += k;
            x += lowbit(x);
        }
    }
    
    inline int ask(int x) {
        int res = 0;
        while (x) {
            res += tr[x];
            x -= lowbit(x);
        }
        return res;
    }
} fenwick;

int main() {
    FastIO
    Cases
    {
        fenwick.clear();
        cin >> n;
        int m = 0;
        for (int i = 1; i * i <= n * 2 - 1; i ++) sq[m ++] = i * i;
        for (int i = 1; i <= n; i ++) cin >> p[i], pos[p[i]] = i;
        int k; cin >> k;
        vector<vector<pii>> q(n + 1);
        for (int i = 0; i < k; i ++) {
            int l, r; cin >> l >> r;
            q[r].emplace_back(i, l);
        }
        int res = 0;
        vector<int> ans(k + 1);
        for (int i = 1; i <= n; i ++) {
            for (int j = 0; j < m; j ++) {
                if (p[i] >= sq[j]) continue;
                if (sq[j] - p[i] > n) break;
                if (pos[sq[j] - p[i]] < i)
                    fenwick.add(pos[sq[j] - p[i]], 1), res ++;
            }
            for (auto [id, l] : q[i]) ans[id] = res - fenwick.ask(l - 1);
        }
        for (int i = 0; i < k; i ++) cout << ans[i] << endl;
    }
    return 0;
}

考虑根号平衡,扫描线插入次数多但查询次数少,树状数组查询和插入均为 O ( l o g   n ) O(log~n) O(log n),故考虑 O ( 1 ) O(1) O(1) 插入、 O ( n ) O(\sqrt n) O(n ) 查询的值域分块来替代

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

using namespace std;
typedef pair<int, int> pii;
const int N = 1e5 + 2, M = 450;
int n, len, sq[M], p[N], pos[N];

struct Blocks {
    int val[N], blk[(int)sqrt(N) + 2];

    void clear() {
        memset(val, 0, sizeof val);
        memset(blk, 0, sizeof blk);
    }

    void update(int x) {
        val[x] ++;
        blk[x / len] ++;
    }

    int query(int x) {
        if (!x) return 0;
        int res = 0;
        while ((x + len) % len != len - 1) res += val[x --];
        if (x < 0) return res;
        x /= len;
        while (x >= 0) res += blk[x --];
        return res;
    }
} blocks;

int main() {
    FastIO
    Cases
    {
        blocks.clear();
        cin >> n;
        len = sqrt(n) + 1;
        int m = 0;
        for (int i = 1; i * i <= n * 2 - 1; i ++) sq[m ++] = i * i;
        for (int i = 1; i <= n; i ++) cin >> p[i], pos[p[i]] = i;
        int k; cin >> k;
        vector<vector<pii>> q(n + 1);
        for (int i = 0; i < k; i ++) {
            int l, r; cin >> l >> r;
            q[r].emplace_back(i, l);
        }
        int res = 0;
        vector<int> ans(k + 1);
        for (int i = 1; i <= n; i ++) {
            for (int j = 0; j < m; j ++) {
                if (p[i] >= sq[j]) continue;
                if (sq[j] - p[i] > n) break;
                if (pos[sq[j] - p[i]] < i)
                    blocks.update(pos[sq[j] - p[i]]), res ++;
            }
            for (auto [id, l] : q[i]) ans[id] = res - blocks.query(l - 1);
        }
        for (int i = 0; i < k; i ++) cout << ans[i] << endl;
    }
    return 0;
}

6-Perfect square number

题意 n n n 个数的序列有 a i ∈ [ 1 , 300 ] a_i\in [1,300] ai[1,300],修改一个数为 [ 1 , 300 ] [1,300] [1,300] 之间的任意值,求完全平方数区间和最多有多少个

题解 计算前缀和,计算前缀/后缀完全平方数区间和数量,枚举修改第几个数,每次加上有关的区间,减去前面无关的区间,结果就是前面与 a i a_i ai 无关的区间加上后面与 a i a_i ai 无关的区间加上刚刚计算出来的与修改过的 a i a_i ai 有关的最多区间数

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

const int N = 602, M = 300;
int n, a[N], prefix[N], suffix[N];
int sum[N], f[N];

inline bool check(int x) {
    return pow((int)sqrt(x), 2) == x;
}

void pre(int l, int r, int k) {
    int now = sum[r] - sum[l - 1];
    for (int i = -M; i <= M; i ++) // 改变值 i
        if (check(now + i)) f[i + M] += k;
}

int solve() {
    memset(prefix, 0, sizeof prefix);
    memset(suffix, 0, sizeof suffix);
    memset(f, 0, sizeof f);
    cin >> n;
    for (int i = 1; i <= n; i ++) cin >> a[i], sum[i] = sum[i - 1] + a[i];
    for (int i = 1; i <= n; i ++) {
        for (int j = 1; j <= i; j ++)
            if (check(sum[i] - sum[j - 1])) prefix[i] ++;
        prefix[i] += prefix[i - 1];
    }
    for (int i = n; i >= 1; i --) {
        for (int j = i; j <= n; j ++)
            if (check(sum[j] - sum[i - 1])) suffix[i] ++;
        suffix[i] += suffix[i + 1];
    }
    int res = 0;
    for (int i = 1; i <= n; i ++) {
        for (int j = i; j <= n; j ++) pre(i, j, 1); // 加上有关的
        for (int j = 1; j <= i - 1; j ++) pre(j, i - 1, -1); // 减去前面无关的
        int now = 0;
        for (int j = 1; j <= M; j ++) now = max(now, f[j - a[i] + M]); // 目标值 j,改变了 j-a[i]
        res = max(res, prefix[i - 1] + suffix[i + 1] + now);
    }
    return res;
}

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

10-Calculate

题意 n n n 个节点的图,保证对于任意节点只有唯一路径到达其他节点,对于每个节点有属性 ( k i , b i , p i ) (k_i,b_i,p_i) (ki,bi,pi),对于每次询问,拿着 y i y_i yi 的值,从点 x i x_i xi 出发,经过 l i l_i li 条边,当到达一个点时 y i ′ = k i y i + b i y_i'=k_iy_i+b_i yi=kiyi+bi,求最终获得的 y i ′ y_i' yi

Tag 倍增

题解 由于可能性太多,且符合结合律( y y y 走一步变成 k i y + b i k_iy+b_i kiy+bi,走两步变成 k i k j x + k j + b j k_ik_jx+k_j+b_j kikjx+kj+bj,两次操作 ( k i , b i ) , ( k j , b j ) (k_i,b_i),(k_j,b_j) (ki,bi),(kj,bj) 可以合成为 ( k i k j , k j b i + b j ) (k_ik_j,k_jb_i+b_j) (kikj,kjbi+bj)),故考虑用倍增来存储从每个点出发走 1 , 2 , 4 , 8 , . . . , 2 i 1,2,4,8,...,2^i 1,2,4,8,...,2i 个长度,预处理相应的 ( k i , b i , p i ) (k_i,b_i,p_i) (ki,bi,pi)

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

typedef long long ll;
const int mod = 1e9 + 7;
const int N = 1e5 + 2, M = 31;
int n, q, p[N][M];
ll k[N][M], b[N][M];

int solve() {
    int x, l, y; cin >> x >> l >> y;
    x = p[x][0];
    for (int i = 0; i < M; i ++) {
        if ((1 << i) & l) {
            y = (y * k[x][i] + b[x][i]) % mod;
            x = p[x][i];
        }
    }
    return y;
}

int main() {
    FastIO
    Cases
    {
        cin >> n >> q;
        for (int i = 1; i <= n; i ++) cin >> k[i][0];
        for (int i = 1; i <= n; i ++) cin >> b[i][0];
        for (int i = 1; i <= n; i ++) cin >> p[i][0];
        for (int j = 1; j <= 30; j ++) {
            for (int i = 1; i <= n; i ++) {
                p[i][j] = p[p[i][j - 1]][j - 1]; // 到达位置
                k[i][j] = k[i][j - 1] * k[p[i][j - 1]][j - 1] % mod;
                b[i][j] = (b[i][j - 1] * k[p[i][j - 1]][j - 1] + b[p[i][j - 1]][j - 1]) % mod;
            }
        }
        while (q --) cout << solve() << endl;
    }
    return 0;
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

JorbanS

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

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

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

打赏作者

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

抵扣说明:

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

余额充值