题意 & 题解
A.Special Permutation
题意:
找一个 (1sim n) 的排列使得 (forall i in[1,n]),(a_i eq i)。多测。
题解:
小构造。
(n) 为偶数,答案是 (nsim 1)。
(n) 为奇数,先输出中位数再 (nsim1)。
#include <cstdio>
#include <cstring>
#include <string>
#include <iostream>
#include <algorithm>
int t, n;
int main() {
scanf("%d", &t);
while (t--) {
scanf("%d", &n);
if (n & 1) {
printf("%d ", n / 2 + 1);
for (int i = n; i >= 1; --i) {
if (i == n / 2 + 1) continue;
printf("%d ", i);
}
}
else {
for (int i = n; i >= 1; --i) printf("%d ", i);
}
puts("");
}
return 0;
}
B.Unique Bid Auction
题意:
找到只出现过一次的最小的数的下标。多测。
题解:
将原数组排序后看是否出现过多次。
#include <cstdio>
#include <cstring>
#include <string>
#include <iostream>
#include <algorithm>
#define M 200010
int t, n;
struct qwer {
int w, id;
friend bool operator < (qwer q1, qwer q2) {
return q1.w < q2.w;
}
}a[M];
int main() {
scanf("%d", &t);
while (t--) {
scanf("%d", &n); int ans = -1;
for (int i = 1; i <= n; ++i) {
scanf("%d", &a[i].w);
a[i].id = i;
}
std::sort(a + 1, a + n + 1);
for (int i = n; i >= 1; --i) {
if (a[i].w != a[i + 1].w && a[i].w != a[i - 1].w) ans = a[i].id;
}
for (int i = 1; i <= n; ++i) {
a[i].w = a[i].id = 0;
}
printf("%d
", ans);
}
return 0;
}
C.Sequence Transformation
题意:
给定一个序列,选择序列中一个数 (x),每次可以删除一段不含 (x) 的区间,问最少多少次序列中只剩下 (x)。多测。
题解:
题目其实就是问出现次数最少的数出现了多少次。连续的一段相同的数按一次算,两端的端点不算。
#include <cstdio>
#include <cstring>
#include <string>
#include <iostream>
#include <algorithm>
#define M 200001
int min(int a, int b) { return a < b ? a : b; }
int t, n, a[M], cnt[M];
int main() {
scanf("%d", &t);
while (t--) {
scanf("%d", &n);
memset(cnt, 0, sizeof cnt);
for (int i = 1; i <= n; ++i) {
scanf("%d", &a[i]);
if (a[i] != a[i - 1]) ++cnt[a[i]];
}
--cnt[a[1]], --cnt[a[n]];
int minn = 2147483647;
for (int i = 1; i <= n; ++i) {
minn = min(minn, cnt[a[i]]);
}
printf("%d
", minn + 1);
}
return 0;
}
D.Number into Sequence
题意:
给一个数 (n),要求找一个长为 (k) 的序列,使得 (forall iin [2,n]),(a_{i-1}mid a_i) 并且 (prodlimits_{i=1}^{n} a_i = n)。要求 (k) 最大。多测。
题解:
根据唯一分解定理 (n) 一定可以写成下面的形式。
(n = {p_1}^{q_1} imes {p_2}^{q_2} imes dots imes {p_n}^{q_n})
如果没有 (forall iin [2,n]),(a_{i-1}mid a_i) 这个要求直接输出每个质因子就是最长的。这个要求就使得下标小的元素含有的质因子,下标大的元素必须含有。所以最长的 (k) 就是 (maxlimits_{i=1}^{n} q_i)。
#include <cmath>
#include <cstdio>
#include <cstring>
#include <string>
#include <iostream>
#include <algorithm>
typedef long long ll;
ll t, n;
void solve(ll x) {
ll k = 0, ans = x, temp = 1, stop = sqrt(x);
for (int i = 2; i <= stop; ++i) {
if (x % i == 0) {
ll k_ = 0;
while (x % i == 0) {
++k_, x /= i;
}
if (k_ > k) k = k_, temp = i;
}
}
if (k == 0) k = 1;
printf("%d
", k);
for (int i = 1; i < k; ++i) {
printf("%lld ", temp);
ans /= temp;
}
printf("%lld
", ans);
}
int main() {
scanf("%lld", &t);
while (t--) {
scanf("%lld", &n);
solve(n);
}
return 0;
}
E.Number of Simple Paths
题意:
给定 (n) 个点 (n) 条边的无向连通图,问其中有多少不同的简单路径。多测。
题解:
图是一个环上面挂着多颗树的样子。
对于每颗树内的路径,设树的根节点为 (v),以 (v) 为根的子树的大小为 (cnt_v)(不包含环中除了 (v) 的其他点)。路径条数为 (dfrac{cnt_v(cnt_v-1)}{2})。
对于从树上走出去的路径条数有 (2 imes cnt_v(n-cnt_v)) 只用统计 (cnt_v(n-cnt_v)) 防止重复。
统计 (cnt_v) 可以使用类似拓扑序的东西。
#include <cstdio>
#include <cstring>
#include <string>
#include <iostream>
#include <algorithm>
#include <queue>
#define M 200001
int cnt[M];
std::queue<int> q;
int t, n, pthn, head[M], ideg[M];
struct Edge {
int nxt, to;
}pth[M << 1];
void add(int frm, int to) {
pth[++pthn].to = to, pth[pthn].nxt = head[frm];
head[frm] = pthn;
}
void format() {
for (int i = 1; i <= n; ++i) ideg[i] = 0;
for (int i = 1; i <= n; ++i) head[i] = 0;
for (int i = 1; i <= pthn; ++i) pth[i].nxt = pth[i].to = 0;
pthn = 0;
}
int main() {
scanf("%d", &t);
while (t--) {
format();
scanf("%d", &n);
for (int i = 1, u, v; i <= n; ++i) {
scanf("%d %d", &u, &v);
add(u, v), add(v, u);
++ideg[u], ++ideg[v];
}
for (int i = 1; i <= n; ++i) {
cnt[i] = 1;
if (ideg[i] == 1) q.push(i);
}
while (!q.empty()) {
int u = q.front(); q.pop();
for (int i = head[u]; i; i = pth[i].nxt) {
int v = pth[i].to;
if (ideg[v] != 1) {
--ideg[v], cnt[v] += cnt[u];
if (ideg[v] == 1) q.push(v);
}
}
}
long long ans = 0;
for (int i = 1; i <= n; ++i) {
if (ideg[i] != 1) ans += 1ll * cnt[i] * (cnt[i] - 1) / 2 + 1ll * cnt[i] * (n - cnt[i]);
}
printf("%lld
", ans);
}
return 0;
}
F.Array Partition
题意:
给一个序列 (a)。找到三个数 (x,y,z) 使得 (x+y+z = n) 并且 (maxlimits_{i=1}^{x}{a_i} = minlimits_{i=x+1}^{x+y}{a_i} = maxlimits_{i=x+y+1}^{n}{a_i})。要求 (x,y,z > 0)。多测。
题解:
枚举第一个区间的右端点 (x),(max1 = maxlimits_{i=1}^{x}{a_i})。
二分第二个区间的右端点 (mid),(min1 = minlimits_{i=x+1}^{mid}{a_i})。
如果 (max1>min1) 第二个区间需要缩小。
如果 (max1<min1) 第二个区间需要扩大。
如果 (max1 = min1) 去判断和第三个区间的关系,(max2 = maxlimits_{i=mid+1}^{n}{a_i})。
如果 (max2 = min1) 代表找到了答案。
如果 (max2 > min1) 第二个区间需要扩大。
如果 (max2 < min1) 第二哥区间需要缩小。
查询最值使用 (st) 表。
#include <cstdio>
#include <cstring>
#include <string>
#include <iostream>
#include <algorithm>
#define M 200001
inline void read(int &T) {
int x = 0;
bool f = 0;
char c = getchar();
while (c < '0' || c > '9') {
if (c == '-') f = !f;
c = getchar();
}
while (c >= '0' && c <= '9') {
x = x * 10 + c - '0';
c = getchar();
}
T = f ? -x : x;
}
int min(int a, int b) { return a < b ? a : b; }
int max(int a, int b) { return a > b ? a : b; }
int t, n, lg[M], min_[M][21], max_[M][21];
int qmax(int l, int r) {
int k = lg[r - l + 1] - 1;
return max(max_[l][k], max_[r - (1 << k) + 1][k]);
}
int qmin(int l, int r) {
int k = lg[r - l + 1] - 1;
return min(min_[l][k], min_[r - (1 << k) + 1][k]);
}
bool solve(int x, int &r) {
int l = x + 1, max1 = qmax(1, x); r = n - 1;
while (l <= r) {
int mid = (l + r) >> 1;
int min1 = qmin(x + 1, mid), max2 = qmax(mid + 1, n);
if (min1 == max1) {
if (max2 == min1) { r = mid; return true; }
if (max2 > min1) l = mid + 1;
if (max2 < min1) r = mid - 1;
}
if (min1 > max1) l = mid + 1;
if (min1 < max1) r = mid - 1;
}
return false;
}
int main() {
read(t);
for (int i = 1; i < M; ++i) {
lg[i] = lg[i - 1] + ((1 << lg[i - 1]) == i);
}
while (t--) {
read(n);
for (int i = 1, x; i <= n; ++i) {
read(x);
min_[i][0] = max_[i][0] = x;
}
for (int j = 1; (1 << j) <= n; ++j) {
for (int i = 1; i + (1 << j) - 1 <= n; ++i) {
min_[i][j] = min(min_[i][j - 1], min_[i + (1 << (j - 1))][j - 1]);
max_[i][j] = max(max_[i][j - 1], max_[i + (1 << (j - 1))][j - 1]);
}
}
int l = -1, r = 0;
for (int i = 1; i < n - 1; ++i) {
if (solve(i, r)) { l = i; break; }
}
if (l == -1) puts("NO");
else {
puts("YES");
//std::cout << qmax(1, l) << " " << qmin(l + 1, r) << " " << qmax(r + 1, n) << '
';
printf("%d %d %d
", l, r - l, n - r);
}
}
return 0;
}
rating & 总结
没有 rating。
我不太行/kk