2018 Multi-University Training Contest 3
Contents
- Problem A. Ascending Rating
- Problem B. Cut The String
- Problem C. Dynamic Graph Matching
- Problem D. Euler Function
- Problem E. Find The Submatrix
- Problem F. Grab The Tree
- Problem G. Interstellar Travel
- Problem H. Monster Hunter
- Problem I. Random Sequence
- Problem J. Rectangle Radar Scanner
- Problem K. Transport Construction
- Problem L. Visual Cube
- Problem M. Walking Plan
Problem A. Ascending Rating
题意:
给出
计算
思路:
单调队列,倒着扫一遍,对于每个区间的
Code
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e7 + 10;
typedef long long ll;
int t;
int n, m, k;
ll p, q, r, mod;
ll arr[maxn];
ll brr[maxn];
int main() {
scanf("%d", &t);
while (t--) {
scanf("%d %d %d %lld %lld %lld %lld", &n, &m, &k, &p, &q, &r, &mod);
for (int i = 1; i <= n; ++i) {
if (i <= k)
scanf("%lld", arr + i);
else
arr[i] = (p * arr[i - 1] + q * i + r) % mod;
}
ll A = 0, B = 0;
int head = 0, tail = -1;
for (int i = n; i > (n - m + 1); --i) {
while (head <= tail && arr[i] >= arr[brr[tail]]) tail--;
brr[++tail] = i;
}
for (int i = n - m + 1; i >= 1; --i) {
while (head <= tail && arr[i] >= arr[brr[tail]]) tail--;
brr[++tail] = i;
while (brr[head] - i >= m) head++;
A += arr[brr[head]] ^ i;
B += (tail - head + 1) ^ i;
}
printf("%lld %lld\n", A, B);
}
return 0;
}
Problem B. Cut The String
留坑。
Problem C. Dynamic Graph Matching
题意:
给出
两种操作,一种是加边,一种是减边,每次加一条或者减一条。
每次操作后输出
问有几种取法,并且任意两个边不能相邻。
思路:
每加一条边,都可以转移状态 比如说 110100
到 111110
就是 dp[111110] += dp[110100]
。
Code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1 << 10;
const int MOD = 1e9 + 7;
int t, n, m;
ll dp[maxn];
ll ans[12];
inline int cal(int x) {
int cnt = 0;
while (x) {
if (x & 1)
cnt++;
x >>= 1;
}
return cnt;
}
int main() {
scanf("%d", &t);
while (t--) {
memset(ans, 0, sizeof ans);
memset(dp, 0, sizeof dp);
dp[0] = 1;
scanf("%d %d", &n, &m);
while (m--) {
char op[10];
int u, v;
scanf("%s %d %d", op, &u, &v);
--u, --v;
for (int s = 0; s < (1 << n); ++s) {
if ((s & (1 << u)) || (s & (1 << v)))
continue;
int S = s | (1 << u);
S |= (1 << v);
if (op[0] == '+') {
dp[S] = (dp[S] + dp[s]) % MOD;
ans[cal(S)] = (ans[cal(S)] + dp[s]) % MOD;
} else if (op[0] == '-') {
dp[S] = (dp[S] - dp[s] + MOD) % MOD;
ans[cal(S)] = (ans[cal(S)] - dp[s] + MOD) % MOD;
}
}
for (int i = 2; i <= n; i += 2) {
printf("%lld%c", ans[i], " \n"[i == n]);
}
}
}
return 0;
}
Problem D. Euler Function
打表找规律。
Code
#include <bits/stdc++.h>
using namespace std;
#define N 100010
inline int gcd(int a, int b) {
return b == 0 ? a : gcd(b, a % b);
}
inline void Init() {
for (int i = 1; i <= 100; ++i) {
int res = 0;
for (int j = 1; j < i; ++j) res += (gcd(i, j) == 1);
printf("%d %d\n", i, res);
}
}
int t, n;
int main() {
scanf("%d", &t);
while (t--) {
scanf("%d", &n);
if (n == 1)
puts("5");
else
printf("%d\n", n + 5);
}
return 0;
}
Problem E. Find The Submatrix
留坑。
Problem F. Grab The Tree
题意:
一棵树,每个点有点权,小 Q 可以选择若干个点,并且任意两个点之间没有边,小 T 就是剩下的所有点,然后两个人的值就是拥有的点异或起来,求小 Q 赢还是输还是平局。
思路:
显然,只有赢或者平局的情况,只要考虑是否有平局情况就可以,当所有点异或起来为
Code
#include <bits/stdc++.h>
using namespace std;
#define N 100010
int t, n;
int arr[N];
int main() {
scanf("%d", &t);
while (t--) {
scanf("%d", &n);
int res = 0;
for (int i = 1; i <= n; ++i) {
scanf("%d", arr + i);
res ^= arr[i];
}
for (int i = 1, u, v; i < n; ++i) scanf("%d%d", &u, &v);
if (res == 0) {
puts("D");
continue;
}
puts("Q");
}
return 0;
}
Problem G. Interstellar Travel
题意:
给出
要从
求从
如果多解输出字典序最小的解。
思路:
可以发现权值就是叉积。
求个凸包。
然后考虑在一条线上的情况。
Code
#include <bits/stdc++.h>
using namespace std;
#define N 200010
const double eps = 1e-8;
inline int sgn(double x) {
if (fabs(x) < eps)
return 0;
if (x < 0)
return -1;
else
return 1;
}
struct Point {
double x, y;
int id;
inline Point() {}
inline Point(double x, double y) : x(x), y(y) {}
inline void scan(int _id) {
id = _id;
scanf("%lf%lf", &x, &y);
}
inline bool operator==(const Point &r) const {
return sgn(x - r.x) == 0 && sgn(y - r.y) == 0;
}
inline bool operator<(const Point &r) const {
return x < r.x || x == r.x && y < r.y || x == r.x && y == r.y && id < r.id;
}
inline Point operator+(const Point &r) const {
return Point(x + r.x, y + r.y);
}
inline Point operator-(const Point &r) const {
return Point(x - r.x, y - r.y);
}
inline double operator^(const Point &r) const {
return x * r.y - y * r.x;
}
inline double distance(const Point &r) const {
return hypot(x - r.x, y - r.y);
}
};
struct Polygon {
int n;
Point p[N];
struct cmp {
Point p;
inline cmp(const Point &p0) {
p = p0;
}
inline bool operator()(const Point &aa, const Point &bb) {
Point a = aa, b = bb;
int d = sgn((a - p) ^ (b - p));
if (d == 0) {
return sgn(a.distance(p) - b.distance(p)) < 0;
}
return d < 0;
}
};
inline void norm() {
Point mi = p[0];
for (int i = 1; i < n; ++i) mi = min(mi, p[i]);
sort(p, p + n, cmp(mi));
}
inline void Graham(Polygon &convex) {
sort(p + 1, p + n - 1);
int cnt = 1;
for (int i = 1; i < n; ++i) {
if (!(p[i] == p[i - 1]))
p[cnt++] = p[i];
}
n = cnt;
norm();
int &top = convex.n;
top = 0;
if (n == 2) {
top = 2;
convex.p[0] = p[0];
convex.p[1] = p[1];
return;
}
if (n == 3) {
top = 3;
convex.p[0] = p[0];
convex.p[1] = p[1];
convex.p[2] = p[2];
return;
}
convex.p[0] = p[0];
convex.p[1] = p[1];
top = 2;
for (int i = 2; i < n; ++i) {
while (top > 1 && sgn((convex.p[top - 1] - convex.p[top - 2]) ^ (p[i] - convex.p[top - 2])) >= 0) {
if (sgn((convex.p[top - 1] - convex.p[top - 2]) ^ (p[i] - convex.p[top - 2])) == 0) {
if (p[i].id < convex.p[top - 1].id)
--top;
else
break;
} else {
--top;
}
}
convex.p[top++] = p[i];
}
if (convex.n == 2 && (convex.p[0] == convex.p[1]))
--convex.n;
}
} arr, ans;
int t, n;
int main() {
scanf("%d", &t);
while (t--) {
scanf("%d", &n);
arr.n = n;
// cout << n << endl;
for (int i = 0; i < n; ++i) arr.p[i].scan(i + 1);
arr.Graham(ans);
for (int i = 0; i < ans.n; ++i) printf("%d%c", ans.p[i].id, " \n"[i == ans.n - 1]);
}
return 0;
}
Problem H. Monster Hunter
留坑。
Problem I. Random Sequence
留坑。
Problem J. Rectangle Radar Scanner
留坑。
Problem K. Transport Construction
留坑。
Problem L. Visual Cube
按题意模拟即可,分块解决。
Code
#include <bits/stdc++.h>
using namespace std;
int t, a, b, c, n, m;
char ans[200][200];
int main() {
scanf("%d", &t);
while (t--) {
memset(ans, 0, sizeof ans);
scanf("%d%d%d", &a, &b, &c);
n = (b + c) * 2 + 1;
m = (a + b) * 2 + 1;
for (int i = n, cnt = 1; cnt <= c; ++cnt, i -= 2) {
for (int j = 1; j <= 2 * a; j += 2) ans[i][j] = '+', ans[i][j + 1] = '-';
}
for (int i = n - 1, cnt = 1; cnt <= c; ++cnt, i -= 2) {
for (int j = 1; j <= 2 * a; j += 2) ans[i][j] = '|';
}
for (int i = 2 * b + 1, tmp = 0, cnt = 1; cnt <= b + 1; ++cnt, i -= 2, tmp += 2) {
for (int j = 1 + tmp, cntt = 1; cntt <= a; ++cntt, j += 2) ans[i][j] = '+', ans[i][j + 1] = '-';
}
for (int i = 2 * b, tmp = 1, cnt = 1; cnt <= b; ++cnt, tmp += 2, i -= 2) {
for (int j = 1 + tmp, cntt = 1; cntt <= a; ++cntt, j += 2) ans[i][j] = '/';
}
for (int j = m, cntt = 1, tmp = 0; cntt <= b + 1; ++cntt, j -= 2, tmp += 2) {
for (int i = 1 + tmp, cnt = 1; cnt <= c + 1; ++cnt, i += 2) {
ans[i][j] = '+';
if (cnt <= c)
ans[i + 1][j] = '|';
}
}
for (int j = m - 1, tmp = 1, cntt = 1; cntt <= b; ++cntt, tmp += 2, j -= 2) {
for (int i = 1 + tmp, cnt = 1; cnt <= c + 1; ++cnt, i += 2) ans[i][j] = '/';
}
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= m; ++j)
if (!ans[i][j])
ans[i][j] = '.';
ans[i][m + 1] = 0;
printf("%s\n", ans[i] + 1);
}
}
return 0;
}
Problem M. Walking Plan
题意:
给出一张图,询问从
思路:
因为
然后查询的时候枚举中间点。
Code
#include <bits/stdc++.h>
using namespace std;
#define N 210
#define INFLL 0x3f3f3f3f3f3f3f3f
#define ll long long
int t, n, m, q;
ll G[N][55][55], dp[N][55][55];
inline void Init() {
memset(G, 0x3f, sizeof G);
memset(dp, 0x3f, sizeof dp);
}
inline void Floyd() {
for (int l = 2; l <= 200; ++l)
for (int k = 1; k <= n; ++k)
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= n; ++j) G[l][i][j] = min(G[l][i][j], G[l - 1][i][k] + G[1][k][j]);
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= n; ++j)
for (int l = 199; l >= 0; --l) G[l][i][j] = min(G[l][i][j], G[l + 1][i][j]); // at least K roads;
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= n; ++j) dp[1][i][j] = G[100][i][j];
for (int l = 2; l <= 100; ++l)
for (int k = 1; k <= n; ++k)
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= n; ++j) dp[l][i][j] = min(dp[l][i][j], dp[l - 1][i][k] + dp[1][k][j]);
}
inline void Run() {
scanf("%d", &t);
while (Init(), t--) {
scanf("%d%d", &n, &m);
for (int i = 1, u, v, w; i <= m; ++i) {
scanf("%d%d%d", &u, &v, &w);
G[1][u][v] = min(G[1][u][v], (ll)w);
}
Floyd();
scanf("%d", &q);
for (int i = 1, u, v, k; i <= q; ++i) {
scanf("%d%d%d", &u, &v, &k);
int unit = floor(k * 1.0 / 100), remind = k - unit * 100;
ll ans = INFLL;
if (k <= 100)
ans = G[k][u][v];
else {
for (int j = 1; j <= n; ++j) ans = min(ans, dp[unit][u][j] + G[remind][j][v]);
}
if (k > 100 && remind == 0)
ans = min(ans, dp[unit][u][v]);
printf("%lld\n", ans >= INFLL ? -1 : ans);
}
}
}
int main() {
#ifdef LOCAL
freopen("Test.in", "r", stdin);
#endif
Run();
return 0;
}
Last update: March 27, 2022
Created: March 27, 2022
Created: March 27, 2022