20200713 T1序列问题
题目描述
\(\text{Tom}\) 的梦想是成为世界冠军。因此他每天都在认真做题。
某天他在学数学的时候又造出了一个新题,并准备以此为难你一下。
给定长度为 \(n\) 的序列,正整数 \(k\),可以定义两个函数:
\(F(i)=i^{a[i]} \ mod \ k\)
\(G(i)=a[i]^{i} \ mod \ k\)
现在要求计算\((l,r)\)数对的数量,其中 \(1 \leq l < r \leq n\),且 \(f(l)>g(r)\)。
输入格式
第 \(1\) 行 \(2\) 个整数 \(n\),\(k\)。
第 \(2\) 行读入 \(n\) 个整数 \(a_1,a_2 \dots a_n\)。
输出格式
一行输出答案。
样例
input1
5 10000
3 1 5 4 2
output1
2
数据规模和限制
对于全部测试数据,满足 \(N \leq 10^5\),\(k \leq 10^9\),\(a_i \leq 10^9\)
各个测试点的数据规模及特殊性质如下表。
测试点 | N | \(a_i\) |
---|---|---|
\(1 \sim 3\) | \(\leq 100\) | \(\leq 100\) |
\(4 \sim 6\) | \(\leq 3000\) | \(\leq 10 ^ 5\) |
\(7 \sim 10\) | \(\leq 10 ^ 5\) | \(\leq 10 ^ 9\) |
题解
先计算出 \(f[i]\) 和 \(g[i]\),然后离散化一下,放到权值线段树上找逆序对个数。
别的找逆序对的方法也行
Code
#include <cstdio>
#include <cstring>
#include <string>
#include <iostream>
#include <algorithm>
#define MAXN 300001
#define lson now << 1
#define rson now << 1 | 1
long long ans;
int n, mod, a[MAXN], f[MAXN], g[MAXN];
struct lsh {
int w, num;
friend bool operator < (lsh x, lsh y) {
return x.w < y.w;
}
}b[MAXN];
struct Node {
int l, r, w;
}tree[MAXN << 1];
void build(int l, int r, int now) {
tree[now].l = l, tree[now].r = r;
if (tree[now].l == tree[now].r) {
tree[now].w = 0;
return;
}
int mid = (tree[now].l + tree[now].r) >> 1;
build(l, mid, lson), build(mid + 1, r, rson);
tree[now].w = tree[lson].w + tree[rson].w;
}
void add(int x, int now) {
if (tree[now].l == tree[now].r) {
++tree[now].w;
return;
}
int mid = (tree[now].l + tree[now].r) >> 1;
if (x <= mid) add(x, lson);
else add(x, rson);
tree[now].w = tree[lson].w + tree[rson].w;
}
int query(int x, int y, int now) {
if (tree[now].l >= x && tree[now].r <= y) return tree[now].w;
int mid = (tree[now].l + tree[now].r) >> 1, ans = 0;
if (x <= mid) ans += query(x, y, lson);
if (y > mid) ans += query(x, y, rson);
return ans;
}
int qpow(int a, int b) {
int ans = 1, base = a;
while(b) {
if (b & 1) ans = 1ll * ans * base % mod;
base = 1ll * base * base % mod;
b >>= 1;
}
return ans % mod;
}
int main() {
scanf("%d %d", &n, &mod);
for (int i = 1; i <= n; ++i) scanf("%d", &a[i]);
for (int i = 1; i <= n; ++i) {
f[i] = qpow(i, a[i]);
b[i].w = f[i];
b[i].num = i;
g[i] = qpow(a[i], i);
b[i + n].w = g[i];
b[i + n].num = -i;
}
std::sort(b + 1, b + 2 * n + 1);
int now = 0;
for (int i = 1; i <= 2 * n; ++i) {
if (b[i].w != b[i - 1].w) ++now;
if (b[i].num > 0) f[b[i].num] = now;
else g[-b[i].num] = now;
}
build(1, 2 * n, 1);
for (int i = n; i > 1; --i) {
add(g[i], 1);
if (f[i - 1] == 1) continue;
ans += query(1, f[i - 1] - 1, 1);
}
printf("%lld\n", ans);
return 0;
}
反思
考场上以为自己写了个 60pts 的算法实际上是 30pts 的算法。写完之后一定要检查啊qwq。