文章目录
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=An−k+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 k≤n
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=n−k+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 l≥r 时,区间 [ 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 1∼n 的排列 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<j≤x 的 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=1∑199999i≈∫1199999x21dx≈3219999923≈5.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) res−query(l−1),也会算上配对 ( 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;
}