2019 ICPC Asia Yinchuan Regional
Posted dup4
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2019 ICPC Asia Yinchuan Regional相关的知识,希望对你有一定的参考价值。
目录
Contest Info
Solved | A | B | C | D | E | F | G | H | I | J | K | L | M | N |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
9/14 | O | O | - | O | - | O | O | O | O | - | O | - | - | O |
- O 在比赛中通过
- ? 赛后通过
- ! 尝试了但是失败了
- - 没有尝试
Solutions
A. Girls Band Party
B. So Easy
题意:
给出一个(n cdot n)的矩形,这个矩形(a_{i, j})的初始值为(0),它每次能够选择一行或者一列加上(1),现在遮住某个位置的数,让你还原这个数。
思路:
考虑倒退操作,不考虑遮住的那个数,然后枚举每行,每列,每次选择行最小,列最小将整行整列减去即可还原出那个数。
代码:
view code
#include <bits/stdc++.h>
using namespace std;
const int N = 1e3 + 10;
int n, a[N][N];
int main() {
while (scanf("%d", &n) != EOF) {
int x = -1, y = -1;
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= n; ++j) {
scanf("%d", &a[i][j]);
if (a[i][j] == -1) {
x = i, y = j;
a[i][j] = 0;
}
}
}
for (int i = 1; i <= n; ++i) {
int Min = 1e9;
for (int j = 1; j <= n; ++j) {
if (x == i && y == j) continue;
Min = min(Min, a[i][j]);
}
for (int j = 1; j <= n; ++j) {
a[i][j] -= Min;
}
}
for (int j = 1; j <= n; ++j) {
int Min = 1e9;
for (int i = 1; i <= n; ++i) {
if (x == i && y == j) continue;
Min = min(Min, a[i][j]);
}
for (int i = 1; i <= n; ++i) {
a[i][j] -= Min;
}
}
printf("%d
", -a[x][y]);
}
return 0;
}
D. Easy Problem
题意:
定义一个序列((a_1, a_2, cdots, a_n))是一个((n, m, d)-good)当且仅当(1 leq a_i leq m(1 leq i leq n))并且(gcd(a_1, a_2, cdots, a_n) = d)
令(f(a, k) = (a_1a_2cdots a_n)^k),现在给出(n, m, d, k),让你求所有合法的((n, m, d)-good)的序列(a)的(f(a, k))
思路:
题目要求的东西等价于:
[
egin{eqnarray*}
f(d) = sumlimits_{a_1 = 1}^m sumlimits_{a_2 = 1}^m cdots sumlimits_{a_n = 1}^m [gcd(a_1, a_2, cdots, a_n) = d](a_1a_2cdots a_n)^k
end{eqnarray*}
]
那么我们令:
[
egin{eqnarray*}
g(d) = sumlimits_{a_1 = 1}^m sumlimits_{a_2 = 1}^m cdots sumlimits_{a_n = 1}^m [d | gcd(a_1, a_2, cdots, a_n)](a_1a_2cdots a_n)^k
end{eqnarray*}
]
显然有:
[
egin{eqnarray*}
g(d) = (sumlimits_{d;|;i} i^k)^n
end{eqnarray*}
]
莫比乌斯反演有:
[
egin{eqnarray*}
f(d) &=& sumlimits_{d;|;i} mu(frac{i}{d})g(i) &=& sumlimits_{d;|;i} mu(frac{i}{d}) (sumlimits_{i;|;j} j^k)^n
end{eqnarray*}
]
所以:
[
f(d) = sumlimits_{i = 1}^{leftlfloor m/d
ight
floor} mu(i) (sumlimits_{id;|;j} j^k)^n
]
代码:
view code
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 1e5 + 10, mod = 59964251;
int pri[N], check[N], mu[N], n, m, d, K, phi;
char s[N];
void sieve() {
memset(check, 0, sizeof check);
*pri = 0;
mu[1] = 1;
for (int i = 2; i < N; ++i) {
if (check[i] == 0) {
pri[++*pri] = i;
mu[i] = -1;
}
for (int j = 1; j <= *pri; ++j) {
if (i * pri[j] >= N) break;
check[i * pri[j]] = 1;
if (i % pri[j] == 0) {
mu[i * pri[j]] = 0;
break;
} else {
mu[i * pri[j]] = -mu[i];
}
}
}
}
int eular(int n) {
int ans = n;
for (int i = 2; i * i <= n; ++i) {
if (n % i == 0) {
ans -= ans / i;
while (n % i == 0)
n /= i;
}
}
if (n > 1) ans -= ans / n;
return ans;
}
ll gcd(ll a, ll b) {
return b ? gcd(b, a % b) : a;
}
ll qmod(ll base, ll n) {
ll res = 1;
while (n) {
if (n & 1) res = res * base % mod;
base = base * base % mod;
n >>= 1;
}
return res;
}
int getMod(int mod) {
int res = 0;
for (int i = 1; s[i]; ++i) {
res = (res * 10 + s[i] - '0') % mod;
}
return res;
}
int main() {
phi = eular(mod);
sieve();
// cout << phi << endl;
int _T; scanf("%d", &_T);
while (_T--) {
scanf("%s%d%d%d", s + 1, &m, &d, &K);
int len = strlen(s + 1);
if (len <= 9) {
n = 0;
for (int i = 1; s[i]; ++i) {
n = n * 10 + s[i] - '0';
}
} else {
n = getMod(phi);
if (getMod(643) == 0 || getMod(93257) == 0) {
n += phi;
}
}
ll res = 0;
for (int i = 1; i <= m / d; ++i) {
int base = 0;
for (int j = i * d; j <= m; j += i * d) {
base += qmod(j, K);
base %= mod;
}
res += 1ll * mu[i] * qmod(base, n) % mod;
res = (res + mod) % mod;
}
printf("%lld
", res);
}
return 0;
}
E. XOR Tree
题意:
定义一个multiset的权值为里面任意两个数的异或和的平方的和。
现在给出一棵有根树((1)为根),每个点有点权,定义(p(x, k))为(x)子树中距离(x)不超过(k)的所有点的点权构成的multiset的权值,现在要对每个(i in [1, n])求(p(i, k))
F. Function!
G. Pot!!
裸的线段树。
代码:
view code
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int n, q;
struct SEG {
struct node {
int Max, lazy;
node() { Max = lazy = 0; }
void up(int x) {
Max += x;
lazy += x;
}
node operator + (const node &other) const {
node res = node();
res.Max = max(Max, other.Max);
return res;
}
}t[N << 2];
void build(int id, int l, int r) {
t[id] = node();
if (l == r) return;
int mid = (l + r) >> 1;
build(id << 1, l, mid);
build(id << 1 | 1, mid + 1, r);
}
void down(int id) {
int &lazy = t[id].lazy;
if (lazy) {
t[id << 1].up(lazy);
t[id << 1 | 1].up(lazy);
lazy = 0;
}
}
void update(int id, int l, int r, int ql, int qr, int v) {
if (l >= ql && r <= qr) {
t[id].up(v);
return;
}
int mid = (l + r) >> 1;
down(id);
if (ql <= mid) update(id << 1, l, mid, ql, qr, v);
if (qr > mid) update(id << 1 | 1, mid + 1, r, ql, qr, v);
t[id] = t[id << 1] + t[id << 1 | 1];
}
int query(int id, int l, int r, int ql, int qr) {
if (l >= ql && r <= qr) return t[id].Max;
int mid = (l + r) >> 1;
down(id);
int res = 0;
if (ql <= mid) res = max(res, query(id << 1, l, mid, ql, qr));
if (qr > mid) res = max(res, query(id << 1 | 1, mid + 1, r, ql, qr));
return res;
}
}seg[4];
int main() {
int id[] = {0, 0, 0, 1, 0, 2, 0, 3, 0};
vector <vector<int>> vec;
vec.resize(15);
for (int i = 2; i <= 10; ++i) {
int x = i;
vec[i].clear();
for (int j = 2; j <= x; ++j) {
while (x % j == 0) {
vec[i].push_back(j);
x /= j;
}
}
// cout << i << endl;
// for (auto &it : vec[i])
// cout << it << " ";
// cout << endl;
}
while (scanf("%d%d", &n, &q) != EOF) {
for (int i = 0; i < 4; ++i) seg[i].build(1, 1, n);
char op[20]; int l, r, x;
while (q--) {
scanf("%s%d%d", op, &l, &r);
if (op[1] == 'U') {
scanf("%d", &x);
for (auto &it : vec[x]) {
seg[id[it]].update(1, 1, n, l, r, 1);
}
} else {
int res = 0;
for (int i = 0; i < 4; ++i) {
res = max(res, seg[i].query(1, 1, n, l, r));
}
printf("ANSWER %d
", res);
}
}
}
return 0;
}
H. Delivery Route
题意:
给出一张图,有(x)条无向边,有(y)条有向边,保证无向边都是正权值,有向边可能有负权值,并且保证如果一条有向边(a_i
ightarrow b_i),那么在该图中,(b_i)不可能到达(a_i)
现在询问从(s)出发到任意一点的最短路。
思路:
我们考虑如果只考虑有向边,那么是一个(DAG),那么把无向边连成的每个联通块看成一个新点,并且有有向边将他们连接起来,他们也是一个(DAG)。
并且无向图的连通块里面没有负权边,可以跑dijkstra,然后根据拓扑序dp一下即可。
代码:
view code
#include <bits/stdc++.h>
using namespace std;
using pII = pair<int, int>;
#define dbg(x...) do { cout << "