题目链接

这场比赛题面英文都好长... ...

A - Zero or One

模拟。

#include <bits/stdc++.h>
using namespace std; int main() {
int a,b,c;
cin>>a>>b>>c;
if(a != b && a!=c) {
cout <<"A";
return 0;
}
if(b != a && b!=c) {
cout <<"B";
return 0;
}
if(a != c && b!=c) {
cout <<"C";
return 0;
}
cout <<"*";
return 0;
}

B - Balloon

找到每一条线段上面那条是什么,然后用并查集就可以求出来每个点最终会到哪里。

寻找每条线段上面那条,可以按照$y$进行排序,然后线段树区间覆盖进行操作。

#include <bits/stdc++.h>
using namespace std; const int maxn = 1e5 + 10;
int n, Q;
struct X {
int x1, y1;
int x2, y2;
}s[maxn];
int nx[maxn];
int f[maxn];
int root[maxn]; int Find(int x) {
if(x != f[x]) f[x] = Find(f[x]);
return f[x];
} bool cmp(const X& a, const X& b) {
if(a.y2 != b.y2) return a.y2 > b.y2;
return a.y1 > b.y1;
} int t[maxn * 40]; void pushDown(int rt) {
if(t[rt] == 0) return;
t[2 * rt] = t[rt];
t[2 * rt + 1] = t[rt];
t[rt] = 0;
} void build(int l, int r, int rt) {
t[rt] = -1;
if(l == r) return;
int mid = (l + r) / 2;
build(l, mid, 2 * rt);
build(mid + 1, r, 2 * rt + 1);
} void update(int L, int R, int val, int l, int r, int rt) {
if(L <= l && r <= R) {
t[rt] = val;
return;
}
pushDown(rt);
int mid = (l + r) / 2;
if(L <= mid) update(L, R, val, l, mid, 2 * rt);
if(R > mid) update(L, R, val, mid + 1, r, 2 * rt + 1);
} int get(int pos, int l, int r, int rt) {
if(l == r) {
return t[rt];
}
pushDown(rt);
int mid = (l + r) / 2;
if(pos <= mid) return get(pos, l, mid, 2 * rt);
else return get(pos, mid + 1, r, 2 * rt + 1);
} int main() {
scanf("%d%d", &n, &Q);
for(int i = 1; i <= n; i ++) {
f[i] = i;
root[i] = 0;
scanf("%d%d", &s[i].x1, &s[i].y1);
scanf("%d%d", &s[i].x2, &s[i].y2);
if(s[i].y1 > s[i].y2) {
swap(s[i].x1, s[i].x2);
swap(s[i].y1, s[i].y2);
}
}
sort(s + 1, s + 1 + n, cmp); for(int i = 1; i <= n; i ++) {
// printf("%d %d %d %d\n", s[i].x1, s[i].y1, s[i].x2, s[i].y2);
} build(0, 1e6 + 10, 1); for(int i = 1; i <= n; i ++) {
if(s[i].y1 == s[i].y2) {
nx[i] = i;
} else {
nx[i] = get(s[i].x2, 0, 1e6 + 10, 1);
}
update(min(s[i].x1, s[i].x2), max(s[i].x1, s[i].x2), i, 0, 1e6 + 10, 1);
} for(int i = 1; i <= n; i ++) {
if(nx[i] == -1 || nx[nx[i]] == nx[i]) {
root[i] = 1;
}
} for(int i = 1; i <= n; i ++) {
if(root[i]) continue;
f[i] = nx[i];
Find(i);
nx[i] = f[i];
} for(int i = 1; i <= n; i ++) {
// printf("%d : %d\n", i, nx[i]);
} while(Q --) {
int x;
scanf("%d", &x);
int id = get(x, 0, 1e6 + 10, 1);
if(id == -1) {
printf("%d\n", x);
continue;
}
if(nx[id] == id) {
printf("%d %d\n", x, s[id].y1);
continue;
}
int now = id, pre = -1;
// printf("!!! %d\n", now);
while(1) {
pre = now;
now = nx[now];
if(now == nx[now] || now == -1) break;
}
if(now == -1) {
printf("%d\n", s[pre].x2);
} else {
printf("%d %d\n", s[pre].x2, s[now].y2);
}
} return 0;
} /*
4 4
0 1 3 3
1 5 6 5
5 3 2 4
7 4 10 2
2
5
8
6 4 3
1 3 4 2
10 3 7 4
2 3 8 3
3 5 5 4
4
9
8 */

C - Boss

模拟,数据范围很少,平方的效率就可以了。

#include <bits/stdc++.h>
using namespace std; const int maxn = 1000;
int n, m, q;
vector<int> g[maxn];
int belong[maxn];
int fac[maxn];
int age[maxn];
int ans;
int f[maxn]; void dfs(int x, int y) {
if(f[x]) return;
// printf("debug %d\n", fac[x]);
f[x] = 1;
if(x != y) ans = min(ans, age[fac[x]]);
for(int i = 0; i < g[x].size(); i ++) {
dfs(g[x][i], y);
}
} int main() {
scanf("%d%d%d", &n, &m, &q);
for(int i = 1; i <= n; i ++) {
belong[i] = i;
fac[i] = i;
scanf("%d", &age[i]);
}
while(m --) {
int u, v;
scanf("%d%d", &u, &v);
g[v].push_back(u);
} while(q --) {
char op[10];
scanf("%s", op);
if(op[0] == 'T') {
int x, y;
scanf("%d%d", &x, &y);
swap(belong[x], belong[y]);
for(int i = 1; i <= n; i ++) {
fac[belong[i]] = i;
}
} else {
int x;
scanf("%d", &x);
ans = 200;
for(int i = 1; i <= n; i ++) {
f[i] = 0;
}
dfs(belong[x], belong[x]);
if(ans == 200) printf("*\n");
else printf("%d\n", ans);
}
}
return 0;
} /*
7 8 9
21 33 33 18 42 22 26
1 2
1 3
2 5
3 5
3 6
4 6
4 7
6 7
P 7
T 4 2
P 7
P 5
T 1 4
P 7
T 4 7
P 2
P 6 6 5 6
10 20 30 40 50 60
1 5
1 4
3 6
2 5
4 5
P 1
P 5
P 6
T 1 6
P 1
P 4 */

D - Folding Machine

爆搜,用序列的hash值进行剪枝。

#include <bits/stdc++.h>
using namespace std; const long long mod = 1e9 + 7;
const long long base = 131LL;
const int maxn = 20;
int n, m;
int a[maxn], b[maxn];
int ans;
int to[maxn]; map<long long, int> ha; long long Get(int x) {
long long res = 0;
for(int i = 1; i <= x; i ++) {
res = res * base % mod;
res = res + to[i];
res = res % mod;
}
return res;
} void dfs(int x) { if(x < m) return; if(x == m) {
int fail = 0;
for(int i = 1; i <= m; i ++) {
if(a[i] != b[i]) fail = 1;
}
if(fail == 0) ans = 1;
// return;
} int tmp[maxn];
for(int i = 1; i <= x; i ++) {
tmp[i] = a[i];
} for(int i = 0; i < x; i ++) {
int left = i;
int right = x - left;
if(max(left, right) < m) continue;
int len = max(left, right);
memset(to, 0, sizeof to);
if(left > right) {
for(int i = 1; i <= left; i ++) {
to[i] = tmp[i];
}
int p = n;
for(int i = left - right + 1; i <= left; i ++) {
to[i] += tmp[p];
p --;
}
} else {
int p = x;
for(int i = 1; i <= right; i ++) {
to[i] = tmp[p];
p --;
}
p = left;
for(int i = right; p; i --) {
to[i] += tmp[p];
p --;
}
} long long to_ha = Get(len);
if(ha[to_ha]) continue;
ha[to_ha] = 1;
for(int i = 1; i <= len; i ++) {
a[i] = to[i];
}
dfs(len); if(ans == 1) return;
} for(int i = 1; i <= x; i ++) {
a[i] = tmp[i];
}
} int main() {
int suma=0,sumb=0;
scanf("%d", &n);
for(int i = 1; i <= n; i ++) scanf("%d", &a[i]), suma += a[i];
scanf("%d", &m);
for(int i = 1; i <= m; i ++) scanf("%d", &b[i]), sumb += b[i]; if(suma == sumb && n >= m)
dfs(n);
if(ans) printf("S\n");
else printf("N\n");
return 0;
} /*
7
5 6 23 8 19 7 10
4
5 16 30 27 7
1 2 3 4 5 6 7
5
7 6 5 5 5 4
1 2 3 4
1
10 6
19 23 3 51 2 0
2
34 64 6
1 2 3 4 5 6
6
1 2 3 4 5 6
*/

E - Dangerous Dive

模拟。

#include <bits/stdc++.h>
using namespace std; const int maxn = 1e5 + 10;
int f[maxn];
vector<int> ans; int main() {
int n, r;
scanf("%d%d", &n, &r);
for(int i = 1; i <= r; i ++) {
int x;
cin >> x;
f[x] = 1;
}
for(int i = 1; i <= n; i ++) {
if(f[i]) continue;
ans.push_back(i);
}
if(ans.size() == 0) {
printf("*");
} else {
for(int i = 0; i < ans.size(); i ++) {
printf("%d", ans[i]);
if(i < ans.size() - 1) printf(" ");
else printf("\n");
}
}
return 0;
}

F - Triangles

枚举起点,然后二分两个中间点。

#include <bits/stdc++.h>
using namespace std; const int maxn = 5e5 + 10;
long long a[maxn];
long long sum[maxn]; int main() {
int n;
scanf("%d", &n);
int ans = 0;
for(int i = 1; i <= n; i ++) {
scanf("%lld", &a[i]);
a[i + n] = a[i];
}
for(int i = 1; i <= 2 * n; i ++) {
sum[i] = sum[i - 1] + a[i];
}
if(sum[n] % 3) {
printf("%d\n", 0);
return 0;
} for(int i = 1; i <= n; i ++) {
int L, R, p; L = i, R = i + n - 1, p = -1;
while(L <= R) {
int mid = (L + R) / 2;
long long num = sum[mid] - sum[i - 1];
if(num == sum[n] / 3) {
p = mid;
break;
} else if(num < sum[n] / 3) {
L = mid + 1;
} else {
R = mid - 1;
}
}
if(p == -1) continue; int tmp = p;
L = p + 1, R = i + n - 1, p = -1;
while(L <= R) {
int mid = (L + R) / 2;
long long num = sum[mid] - sum[tmp];
if(num == sum[n] / 3) {
p = mid;
break;
} else if(num < sum[n] / 3) {
L = mid + 1;
} else {
R = mid - 1;
}
}
if(p == -1) continue;
//printf("debug : %d\n", i);
ans ++;
}
printf("%d\n", ans / 3);
return 0;
} /*
8
4 2 4 2 2 6 2 2 6
3 4 2 1 5 3
*/

G - Lines of Containers

可以发现,行列是独立的。即我们可以抓出每行的最小值,按最小值进行行调整。然后随便抓一行,按这一行的列上的值进行调整,这一行调整完毕之后检查其余行。

#include <bits/stdc++.h>
using namespace std; int a[500][500];
int mn[500];
int tmp[500];
int n, m;
int ans; void swapR(int x, int y) {
for(int j = 1; j <= m; j ++) {
swap(a[x][j], a[y][j]);
}
} void swapC(int x, int y) {
for(int i = 1; i <= n; i ++) {
swap(a[i][x], a[i][y]);
}
} int main() {
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i ++) {
mn[i] = 1000000;
for(int j = 1; j <= m; j ++) {
scanf("%d", &a[i][j]);
mn[i] = min(mn[i], a[i][j]);
}
} int fail = 0; for(int i = 1; i <= n; i ++) {
tmp[i] = mn[i];
}
sort(tmp + 1, tmp + n + 1); for(int i = 1; i <= n; i ++) {
if(tmp[i] == mn[i]) continue;
int pos;
for(int j = 1; j <= n; j ++) {
if(mn[j] == tmp[i]) pos = j;
}
ans ++;
swap(mn[i], mn[pos]);
swapR(i, pos);
} for(int j = 1; j <= m; j ++) {
tmp[j] = mn[j] = a[1][j];
}
sort(tmp + 1, tmp + m + 1); for(int j = 1; j <= m; j ++) {
if(tmp[j] == mn[j]) continue;
int pos;
for(int i = 1; i <= m; i ++) {
if(mn[i] == tmp[j]) pos = i;
}
ans ++;
swap(mn[j], mn[pos]);
swapC(j, pos);
} int num = 1;
for(int i = 1; i <= n; i ++) {
for(int j = 1; j <= m; j ++) {
if(a[i][j] != num) fail = 1;
num ++;
}
} if(fail) {
printf("*");
} else {
printf("%d\n", ans);
} return 0;
} /* 2 2
3 4
1 2 3 3
9 2 4
5 8 7
6 1 3 5 4
13 15 14 16
5 7 6 8
9 11 10 12
1 3 2 4
17 19 18 20 */

H - Buses

斐波那契数列变了一下,方案数${f_i} = L \times {f_{i - 2}} + K \times {f_{i - 1}}$矩阵快速幂加速即可

#include <bits/stdc++.h>
using namespace std; const long long mod = 1e6; long long n, K, L; struct Matrix
{
long long A[4][4];
int R, C;
Matrix operator*(Matrix b);
}; Matrix Matrix::operator*(Matrix b)
{
Matrix c;
memset(c.A,0,sizeof(c.A));
int i,j,k;
for(i=1; i<=R; i++)
for(j=1; j<=b.C; j++)
for(k=1; k<=C; k++)
c.A[i][j]=((A[i][k]*b.A[k][j])%mod+c.A[i][j])%mod;
c.R=R; c.C=b.C;
return c;
} Matrix X, Y, Z; long long init(long long a, long long b, long long c)
{
b = b % mod;
c = c % mod; memset(X.A,0,sizeof X.A);
memset(Y.A,0,sizeof Y.A);
memset(Z.A,0,sizeof Z.A); Z.A[1][1] = 1;
Z.A[1][2] = b;
Z.R = 1; Z.C = 2; for(int i=1;i<=2;i++) Y.A[i][i]=1;
Y.R = 2; Y.C = 2; X.A[1][1] = 0; X.A[1][2] = c;
X.A[2][1] = 1; X.A[2][2] = b;
X.R = 2; X.C = 2; while (a)
{
if (a % 2 == 1) Y = Y*X;
a = a >> 1;
X = X*X;
}
Z = Z*Y; return Z.A[1][1];
} int main() {
cin >> n >> K >> L;
n /= 5;
printf("%06lld\n", init(n, K, L));
return 0;
}

I - Patches

$dp[i]$表示修补到$i$个洞为止的最小花费。

感觉这题可以加强一下,因为轮子是一个环,再加上一个枚举起点也不算过分吧...

#include <bits/stdc++.h>
using namespace std; const int maxn = 2000;
int n;
int a[maxn];
int dp[maxn];
int t1, t2;
int C; int main() {
scanf("%d%d%d%d", &n, &C, &t1, &t2);
for(int i = 1; i <= n; i ++) {
scanf("%d", &a[i]);
}
sort(a + 1, a + 1 + n);
for(int i = 1; i <= n; i ++) {
dp[i] = dp[i - 1] + min(t1, t2);
int pos1 = -1, pos2 = -1;
for(int j = i - 1; j >= 1; j --) {
if(a[i] - a[j] <= t1) pos1 = j;
if(a[i] - a[j] <= t2) pos2 = j;
}
if(pos1 != -1) {
dp[i] = min(dp[i], dp[pos1 - 1] + t1);
}
if(pos2 != -1) {
dp[i] = min(dp[i], dp[pos2 - 1] + t2);
}
}
printf("%d\n", dp[n]);
return 0;
} /*
5 20 2 3
2 5 8 11 15 4 20 12 9
1 2 3 13
*/

J - Trucks

先求出最大生成树,这个时候把必要的长度最长的边都保留下来了。

对于每一次的询问,就是求两点的路径上的最小权值,可以倍增处理。

#include <bits/stdc++.h>
using namespace std; const int maxn = 2e5 + 10;
int n, m, Q;
struct Edge {
int u, v, w;
}e[maxn]; int belong[maxn]; int h[maxn], to[maxn], cost[maxn], nx[maxn], cnt;
int f[maxn], dep[maxn], too[maxn][35], mn[maxn][35], idx[maxn][35]; void add(int u, int v, int c) {
to[cnt] = v;
nx[cnt] = h[u];
cost[cnt] = c;
h[u] = cnt ++;
} int Find(int x) {
if(x != belong[x]) return belong[x] = Find(belong[x]);
return belong[x];
} bool cmp(const Edge &a, const Edge &b) {
return a.w > b.w;
} void dfs(int fa,int x,int y,int eid)
{
f[x]=fa; dep[x]=y;
if(x==1)
{
too[x][0] = -1;
mn[x][0] = 1e6;
}
else
{
too[x][0] = fa;
mn[x][0] = cost[eid];
} for(int j=1;j<=30;j++)
{
if((1<<j) > dep[x]-1) {
too[x][j] = -1;
mn[x][j] = 1e6;
} else {
too[x][j] = too[too[x][j-1]][j-1];
mn[x][j] = min(mn[x][j-1], mn[too[x][j-1]][j-1]);
}
} for(int i = h[x]; i != -1; i = nx[i])
{
int v = to[i];
if(v == fa) continue;
if(f[v] != 0) continue;
dfs(x, v, y + 1, i);
}
} int F(int a,int b)
{
if(dep[a]<dep[b]) swap(a,b); int MN=1e6;
if(dep[a]!=dep[b])
{
while(1)
{
int L=0,R=30,pos;
while(L<=R)
{
int mid=(L+R)/2;
if(too[a][mid]!=-1&&dep[too[a][mid]]>=dep[b]) L=mid+1,pos=mid;
else R=mid-1;
} if(mn[a][pos]<=MN) MN=mn[a][pos]; a=too[a][pos];
if(dep[a]==dep[b]) break;
}
} if(a==b) return MN; while(1)
{
if(f[a]==f[b])
{
if(mn[a][0]<=MN) MN=mn[a][0];
if(mn[b][0]<=MN) MN=mn[b][0];
break;
} int L=0,R=30,pos;
while(L<=R)
{
int mid=(L+R)/2;
if(too[a][mid]!=too[b][mid]) L=mid+1,pos=mid;
else R=mid-1;
} if(mn[a][pos]<=MN) MN=mn[a][pos];
if(mn[b][pos]<=MN) MN=mn[b][pos]; a=too[a][pos];
b=too[b][pos];
} return MN;
} int main() {
scanf("%d%d%d", &n, &m, &Q);
for(int i = 1; i <= n; i ++) {
belong[i] = i;
h[i] = -1;
}
for(int i = 1; i <= m; i ++) {
scanf("%d%d%d", &e[i].u, &e[i].v, &e[i].w);
}
sort(e + 1, e + 1 + m, cmp); for(int i = 1; i <= m; i ++) {
int fa = Find(e[i].u);
int fb = Find(e[i].v);
if(fa == fb) continue;
belong[fa] = fb;
// printf("debug %d %d %d\n", e[i].u, e[i].v, e[i].w);
add(e[i].u, e[i].v, e[i].w);
add(e[i].v, e[i].u, e[i].w);
} dfs(-1, 1, 1, -1); while(Q --) {
int x, y;
scanf("%d%d", &x, &y);
printf("%d\n", F(x, y));
} return 0;
} /*
4 5 4
1 2 9
1 3 0
2 3 8
2 4 7
3 4 4
1 4
2 1
3 1
4 3 4 5 2
1 2 30
2 3 20
3 4 10
4 1 40
2 4 50
1 3
1 2 */

最新文章

  1. 闭包内的微观世界和js垃圾回收机制
  2. Google Authentication 机制原理
  3. C/C++学习站点资源
  4. css(html)背景图优化合并
  5. 【python自动化第七篇:面向对象进阶】
  6. About Health Monitor Checks
  7. Java简单记录
  8. 转:Loadrunner——Block(块)技术
  9. meta 是什么??
  10. scala写算法-快排
  11. async &amp; await 异步编程的一点巧方法
  12. java学习日记-基础-列出2~100内的素数
  13. Linux安装配置Mariadb
  14. ps入门学习
  15. Selenium Extent Report的设置
  16. 网易云信&amp;七鱼市场总监姜菡钰:实战解读增长黑客在B端业务的运用
  17. Alpha Version Release Of Teamwork: Appendix 1 BUG BASH
  18. 【Unity】1.0 第1章 Unity—3D游戏开发和虚拟现实应用开发的首选
  19. centos6 mysql 安装与配置
  20. Flash CC2015软件安装教程

热门文章

  1. Nginx配置——区分PC或手机访问不同域名以及http跳转https
  2. RabbitMQ的安装部署
  3. webpack进阶--loader
  4. yolo详解
  5. CXF wsdl2java 生成java代码供客户端使用
  6. redis添加systemctl服务
  7. bzoj千题计划253:bzoj2154: Crash的数字表格
  8. bzoj千题计划233:bzoj 1304: [CQOI2009]叶子的染色
  9. C++ map &amp; set
  10. Kubernetes之解决从k8s.gcr.io拉取镜像失败问题