AtCoder Regular Contest 089

4 篇文章 0 订阅
4 篇文章 0 订阅

比赛链接

C - Traveling

题意:

有一个平面,初始时在(0,0)点。每次可以花一个时间走到上下左右四个方向。
现在给n个询问,每次询问t,x,y,表示在t时刻是否能到达(x,y)这个坐标。可以输出Yes,否则输出No。

做法:

发现只有两种情况是No:

  1. 来不及了,时间小于距离。
  2. 距离与时间的差值是奇数。

代码:

#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。
需要满足:

  1. n<=300
  2. 没有重边和自环
  3. 顶点编号为1~n
  4. 每条边的边权有三种,’X’,’Y’或者一个整数
  5. 给定一个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)
争取早点上蓝啊。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值