C - Traveling
题意:
有一个平面,初始时在(0,0)点。每次可以花一个时间走到上下左右四个方向。
现在给n个询问,每次询问t,x,y,表示在t时刻是否能到达(x,y)这个坐标。可以输出Yes,否则输出No。
做法:
发现只有两种情况是No:
- 来不及了,时间小于距离。
- 距离与时间的差值是奇数。
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<cctype>
using namespace std;
typedef long long ll;
int main() {
int n;
scanf("%d", &n); int nx = 0, ny = 0, lst = 0;
for(int i = 1; i <= n; i ++) {
int x, y, t;
scanf("%d%d%d", &t, &x, &y);
int dis = abs(x-nx)+abs(y-ny);
if(dis > t-lst) { puts("No"); return 0; }
if((t-lst-dis)&1) { puts("No"); return 0; }
nx = x; ny = y; lst = t;
} puts("Yes");
return 0;
}
D - Checker
题意:
给你n个点的坐标,和他们要染成的颜色(黑或白)。
现在有一个单位长度为k的黑白棋盘状的布(可以这么理解吧qwq)让你覆盖这个平面。
问怎样覆盖才能使得n个点里面最多个数的点满足要求。
做法:
我们把所有的点缩到一个2k*2k的棋盘上。(就是所有点的坐标都%2k)
然后记录一下这个棋盘上每个格子有多少黑点多少白点,然后求一下二维前缀和。
然后我们考虑枚举一个起点(i,j),表示(i,j)~(i+k-1,j+k-1)这一个矩形全为黑(白),以这个为基准扩展开去。
就是看这个图:
其中红色部分和白色部分就刚好放黑白两种颜色。
于是问题就转换为求这些方块内黑、白色点的个数,假设红色部分放黑点,那就求出红色块内黑点的个数和白色块内白点的个数和;红色部分放白点同理,用预处理好的二维前缀和就可以解决。于是k^2枚举一下,取答案的最大值即可。
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<cctype>
using namespace std;
typedef long long ll;
const int N = 2010;
int n, k;
int a[N][N], b[N][N];
char ch[5];
inline int sum(int a[N][N], int i, int j, int x, int y) {
return a[x][y]-a[x][j-1]-a[i-1][y]+a[i-1][j-1];
}
inline int cal(int a[N][N], int i, int j) {
int ret = sum(a, i, j, i+k-1, j+k-1)+sum(a, 1, 1, i-1, j-1)+sum(a, i+k, j+k, k<<1, k<<1);
ret += sum(a, i+k, 1, k<<1, j-1)+sum(a, 1, j+k, i-1, k<<1);
return ret;
}
int main() {
scanf("%d%d", &n, &k);
for(int i = 1; i <= n; i ++) {
int x, y; scanf("%d%d%s", &x, &y, ch);
x %= (k<<1); y %= (k<<1); x ++, y ++;
if(ch[0] == 'W') a[x][y] ++; else b[x][y] ++;
}
for(int i = 1; i <= k<<1; i ++)
for(int j = 1; j <= k<<1; j ++) {
a[i][j] += a[i][j-1] + a[i-1][j] - a[i-1][j-1];
b[i][j] += b[i][j-1] + b[i-1][j] - b[i-1][j-1];
} int ans = 0;
for(int i = 1; i <= k; i ++)
for(int j = 1; j <= k; j ++) {
int tmp = cal(a, i, j);
int tmpp = cal(b, i, j);
tmpp = b[k<<1][k<<1] - tmpp;
ans = max(ans, tmp+tmpp);
tmp = cal(b, i, j);
tmpp = cal(a, i, j);
tmpp = a[k<<1][k<<1] - tmpp;
ans = max(ans, tmp+tmpp);
}
printf("%d\n", ans);
return 0;
}
E - GraphXY
题意:
你要构造一个n个点m条边的有向图,并指定一个s,t。
需要满足:
- n<=300
- 没有重边和自环
- 顶点编号为1~n
- 每条边的边权有三种,’X’,’Y’或者一个整数
- 给定一个A,B,对于所有数对(x,y),1<=x<=A,1<=y<=B,此时途中边为’X’的边权为x,边为’Y’的边权为y,要求s-t的最短路长度刚好为d_{x,y}。d数组给定。
其中1<=A,B<=10。
做法:
我们考虑这样一种构造方式:202个点,前101个为一条链,全部是’X’,后101个为一条链,全部是’Y’。两条链之间会有一些边,为满足最短路=d_{x,y}的要求。
这样子最多300条边(好巧啊qaq)
我们枚举一个i,j,k,表示前101个点中第i条边的那个点,后101个点中最后第j条边的那个点,这两个点的边权为k。然后检验O(A*B)检验是否满足要求。
(这样似乎很容易被卡但是出题人并没有卡emmm)
然后就输出答案好了。注意判重边。
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<cctype>
using namespace std;
typedef long long ll;
int a, b;
int d[15][15];
struct edge {
int x, y, z;
edge() { x = y = z = 0; }
edge(int a, int b, int c) { x = a, y = b, z = c; }
}ans[15][15];
int vis[300][300];
int main() {
scanf("%d%d", &a, &b);
for(int i = 1; i <= a; i ++)
for(int j = 1; j <= b; j ++) scanf("%d", &d[i][j]);
for(int i = 0; i <= 100; i ++)
for(int j = 0; j <= 100; j ++)
for(int k = 0; k <= 100; k ++) {
bool flag = 0;
for(int t1 = 1; t1 <= a; t1 ++)
for(int t2 = 1; t2 <= b; t2 ++)
if(i*t1+j*t2+k < d[t1][t2]) flag = 1;
if(flag) continue;
for(int t1 = 1; t1 <= a; t1 ++)
for(int t2 = 1; t2 <= b; t2 ++)
if(i*t1+j*t2+k == d[t1][t2]) ans[t1][t2] = edge(i+1, j+1, k);
break;
}
bool chk = 0;
for(int i = 1; i <= a; i ++)
for(int j = 1; j <= b; j ++) if(ans[i][j].x == 0) { puts("Impossible"); return 0; }
puts("Possible"); int n = 200;
for(int i = 1; i <= a; i ++)
for(int j = 1; j <= b; j ++) if(!vis[ans[i][j].x][ans[i][j].y]) n ++, vis[ans[i][j].x][ans[i][j].y] = 1;
printf("202 %d\n", n); memset(vis, 0, sizeof vis);
for(int i = 1; i < 101; i ++) printf("%d %d X\n", i, i+1);
for(int i = 102; i < 202; i ++) printf("%d %d Y\n", i, i+1);
for(int i = 1; i <= a; i ++)
for(int j = 1; j <= b; j ++) if(ans[i][j].x) {
if(!vis[ans[i][j].x][ans[i][j].y]) printf("%d %d %d\n", ans[i][j].x, 202-ans[i][j].y+1, ans[i][j].z);
vis[ans[i][j].x][ans[i][j].y] = 1;
}
puts("1 202");
return 0;
}
总结:
比赛时通过CD,rank 207,rating 1289->1428。
emmm (D题搞了1h是不是有点太菜了啊是的吧qaq)
争取早点上蓝啊。。