A题意:给你个黑白矩阵,每次黑的周围一圈会变黑,求多少次之后全黑。n <= 1000

解:BFS即可。

 #include <bits/stdc++.h>

 const int N = ;
const int dx[] = {, , -, };
const int dy[] = {, , , -}; struct Node {
int x, y;
Node(int X = , int Y = ) {
x = X;
y = Y;
}
}; int vis[N][N], d[N][N];
char str[N];
std::queue<Node> Q; int main() { int n, m, ans = ;
scanf("%d%d", &n, &m);
for(int i = ; i <= n; i++) {
scanf("%s", str + );
for(int j = ; j <= m; j++) {
if(str[j] == '#') {
Q.push(Node(i, j));
vis[i][j] = ;
d[i][j] = ;
}
}
} while(Q.size()) {
int x = Q.front().x, y = Q.front().y;
Q.pop();
for(int i = ; i < ; i++) {
int tx = x + dx[i], ty = y + dy[i];
if(tx < || ty < || tx > n || ty > m || vis[tx][ty]) {
continue;
}
vis[tx][ty] = ;
d[tx][ty] = d[x][y] + ;
Q.push(Node(tx, ty));
ans = std::max(ans, d[tx][ty]);
}
}
printf("%d\n", ans);
return ;
}

AC代码

B题意:给你个矩阵,初始时有个棋子在(sx,sy)。先后手都有个字符串,每一回合可以选择不走或者按照字符串上的方向走一步。先手想要玩完n回合,后手想要在n回合之内把棋子走出棋盘。谁能如愿以偿呢?n <= 20w

解:发现行列独立。于是考虑行。我们从后往前,维护第i步时棋子在哪些地方会导致在n步内出棋盘。判断一下是否必出棋盘即可。列同理。

 #include <bits/stdc++.h>

 const int N = ;

 char str1[N], str2[N];
int n; int main() { int n1, n2, x1, x2;
scanf("%d%d%d", &n1, &n2, &n);
scanf("%d%d", &x1, &x2);
scanf("%s%s", str1 + , str2 + ); bool f = ;
int L = , R = n1 + ;
for(int i = n; i >= ; i--) { if(str2[i] == 'L' || str2[i] == 'R') { }
else if(str2[i] == 'D') {
L = std::max(L - , );
}
else {
R = std::min(R + , n1 + );
} if(str1[i] == 'L' || str1[i] == 'R') { }
else if(str1[i] == 'D') {
R = R - ;
}
else {
L = L + ;
}
if(L + >= R) {
f = ;
break;
} }
if(x1 <= L || R <= x1) {
f = ;
}
L = , R = n2 + ;
for(int i = n; i >= && f; i--) { if(str2[i] == 'U' || str2[i] == 'D') { }
else if(str2[i] == 'L') {
R = std::min(R + , n2 + );
}
else {
L = std::max(L - , );
} if(str1[i] == 'U' || str1[i] == 'D') { }
else if(str1[i] == 'L') {
L = L + ;
}
else {
R = R - ;
}
if(L + >= R) {
f = ;
break;
} }
if(x2 <= L || R <= x2) {
f = ;
}
if(f) {
printf("YES\n");
}
else {
printf("NO\n");
}
return ;
}

AC代码

C题意:给你一棵树,每个点上有一个硬币。两个人轮流选择一个有硬币的点,把该点的硬币取走并把其它点的硬币都向这个点挪一步。不能操作者输。问谁输?n <= 20w

解:发现与每个点的具体硬币数量没关系,只跟是否有硬币有关系。然后发现每一次就是删掉所有叶子,但是你可以选择保护一个叶子不被删。我们感性想象一下,发现跟每某个点的伸出去的最长链有关系...

然后考虑直径,别问我怎么想到的...灵光一闪就想到了。发现每次操作之后,直径要么减2要么减1,就算直径改变了,但是长度仍然遵守这个规律。且最后剩下来的是一条单个的直径。于是求出直径长度,sg函数即可。(其实有个规律......)

 #include <bits/stdc++.h>

 const int N = ;

 struct Edge {
int nex, v;
}edge[N << ]; int tp; int n, e[N], sg[N], f[N], Ans; inline void add(int x, int y) {
edge[++tp].v = y;
edge[tp].nex = e[x];
e[x] = tp;
return;
} void DFS(int x, int fa) {
int a = , b = ;
for(int i = e[x]; i; i = edge[i].nex) {
int y = edge[i].v;
if(y == fa) continue;
DFS(y, x);
if(a < f[y] + ) {
b = a;
a = f[y] + ;
}
else {
b = std::max(b, f[y] + );
}
}
Ans = std::max(Ans, std::max(a + b - , a));
f[x] = a;
return;
} int main() { int n;
scanf("%d", &n);
for(int i = , x, y; i < n; i++) {
scanf("%d%d", &x, &y);
add(x, y);
add(y, x);
} DFS(, ); /// cal Ans
sg[] = ;
sg[] = ;
for(int i = ; i <= Ans; i++) {
if(std::min(sg[i - ], sg[i - ]) == ) {
sg[i] = ;
}
else {
sg[i] = ;
}
} if(sg[Ans]) {
printf("First\n");
}
else {
printf("Second\n");
} return ;
}

AC代码

D题意:给你一个黑白矩阵,求它的复杂度。定义一个矩阵的复杂度为:纯色矩阵为0,否则横/竖切一刀,这种划分方式的权值为两个子矩阵的复杂度的max。这个矩阵的复杂度为所有划分方式的权值中的最小值 + 1。n <= 185, 5s。

解:考虑到复杂度不会超过2log,于是设fijkl为左边界为i,上下边界为jk,复杂度为l的矩形右边界最远能到的列。转移的时候有一个非常优秀的单调指针,不知道为什么......

 #include <bits/stdc++.h>

 const int N = ;

 short G[N][N], a[N][N][N][], b[N][N][N][], sum1[N][N], sum2[N][N]; /// a->  b|
char str[N]; inline short get1(short l, short r, short i) { /// |
return sum1[r][i] - sum1[l - ][i];
}
inline short get2(short i, short l, short r) { /// -
return sum2[i][r] - sum2[i][l - ];
} inline void exmax(short &a, const short &b) {
a < b ? a = b : ;
return;
}
inline short Min(const short &a, const short &b) {
return a > b ? b : a;
} int main() { //printf("%d \n", (sizeof(a) * 2 + sizeof(G) + sizeof(str)) / 1048576);
short n, m;
scanf("%hd%hd", &n, &m);
for(register short i(); i <= n; ++i) {
scanf("%s", str + );
for(register short j(); j <= m; ++j) {
G[i][j] = (str[j] == '#');
sum1[i][j] = sum1[i - ][j] + G[i][j];
sum2[i][j] = sum2[i][j - ] + G[i][j];
//printf("%hd %hd G = %hd \n", i, j, G[i][j]);
}
} for(register short l(); l <= n; ++l) {
for(register short r(l); r <= n; ++r) {
short last = -;
for(register short i(m); i >= ; --i) {
short tot(get1(l, r, i));
//printf("tot = %hd \n", tot);
if(tot != && tot != r - l + ) {
a[l][r][i][] = i - ;
last = -;
}
else if(last != tot) {
a[l][r][i][] = i;
last = tot;
}
else {
a[l][r][i][] = a[l][r][i + ][];
}
//printf("a %hd %hd %hd 0 = %hd \n", l, r, i, a[l][r][i][0]);
}
}
} /*for(short l = 1; l <= m; l++) {
for(short r = l; r <= m; r++) {
short last = -1;
for(short i = n; i >= 1; i--) {
short tot = get2(i, l, r);
//printf("tot = %hd \n", tot);
if(tot != r - l + 1 && tot != 0) {
b[i][l][r][0] = i - 1;
last = -1;
}
else if(tot != last) {
b[i][l][r][0] = i;
last = tot;
}
else {
b[i][l][r][0] = b[i + 1][l][r][0];
}
//printf("b %hd %hd %hd 0 = %hd \n", i, l, r, b[i][l][r][0]);
}
}
}*/ if(a[][n][][] == m) {
printf("%hd\n", );
return ;
} for(register short j(); j <= ; ++j) { //printf("------------------- %hd -------------------- \n", j);
for(register short i(m); i >= ; --i) {
for(register short l(); l <= n; ++l) {
short p = l;
for(register short r(l); r <= n; ++r) {
exmax(a[l][r][i][j], a[l][r][i][j - ]);
short t(a[l][r][i][j - ]);
t = a[l][r][t + ][j - ];
exmax(a[l][r][i][j], t);
if(a[l][r][i][j] == m || l == r) continue; for(; p < r; ++p) {
/// p [l, p] [p + 1, r]
t = Min(a[l][p][i][j - ], a[p + ][r][i][j - ]);
// if(a[l][p][i][j - 1] <= a[l][r][i][j]) break;
if(a[l][p][i][j - ] == i - ) break;
if(p == r - || Min(a[l][p + ][i][j - ], a[p + ][r][i][j - ]) < t) {
exmax(a[l][r][i][j], t);
break;
}
} }
}
if(a[][n][][j] == m) {
printf("%hd\n", j);
return ;
}
} /*for(short l = 1; l <= n; l++) {
for(short r = l; r <= n; r++) {
for(short i = 1; i <= m; i++) {
printf("a %hd %hd %hd = %hd \n", l, r, i, a[l][r][i][j]);
}
}
}
printf("--------------- \n");
for(short l = 1; l <= m; l++) {
for(short r = l; r <= m; r++) {
for(int i = 1; i <= n; i++) {
printf("b %hd %hd %hd = %hd \n", i, l, r, b[i][l][r][j]);
}
}
}
puts("");*/
} /*for(register short i = 0; i <= 17; i++) {
if(a[1][n][1][i] == m) {
printf("%hd\n", i);
break;
}
if(b[1][1][m][i] == n) {
printf("%hd\n", i);
break;
}
}*/ return ;
}

AC代码

agc033的更多相关文章

  1. 【AtCoder】AGC033(A-F)

    AGC033 A - Darker and Darker 直接BFS #include <bits/stdc++.h> #define fi first #define se second ...

  2. AGC033 D~F——[ 值放到角标的DP ][ 思路+DP ][ 思路 ]

    地址:https://atcoder.jp/contests/agc033/ D Complexity dp[ i ][ j ][ k ][ l ] 表示左上角是 ( i , j ) .右下角是 ( ...

  3. AtCoder整理(持续更新中……)

    做了那么久的atcoder觉得自己的题解发的很乱 给有想和我一起交流atcoder题目(或者指出我做法的很菜)(或者指责我为什么整场比赛只会抄题解)的同学一个索引的机会??? 于是写了个爬虫爬了下 A ...

随机推荐

  1. Java开发系列-JDBC

    概述 JDBC(Java DataBase Connectivity,java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和 ...

  2. JS规则 较量较量(比较操作符) 两个操作数通过比较操作符进行比较,得到值为真(true)和假(false)。【>; <; >=; <=; !=;==】

    较量较量(比较操作符) 我们先来做道数学题,数学考试成绩中,小明考了90分,小红考了95分,问谁考的分数高? 答: 因为"95 > 90",所以小红考试成绩高. 其中大于号& ...

  3. linux系统使用小记

    1.解决Ubuntu不能正常使用vi的问题.sudo apt-get remove vim-common   sudo apt-get install vim 2.备份linux系统,注意,有的优盘单 ...

  4. CF596D Wilbur and Trees

    题意:有一些高度为h的树在数轴上.每次选择剩下的树中最左边或是最右边的树推倒(各50%概率),往左倒有p的概率,往右倒1-p. 一棵树倒了,如果挨到的另一棵树与该数的距离严格小于h,那么它也会往同方向 ...

  5. slam课程

    美国宾夕法尼亚大学最近有录制一套 无人机视觉定位导航相关的视频课程,2019年3月份在YouTube上更新完毕,质量非常高,名字叫Robotics,视频课程列表:https://www.youtube ...

  6. pytorch 入门指南

    两类深度学习框架的优缺点 动态图(PyTorch) 计算图的进行与代码的运行时同时进行的. 静态图(Tensorflow <2.0) 自建命名体系 自建时序控制 难以介入 使用深度学习框架的优点 ...

  7. 安卓手机端微信网页浏览记录清理debugx5.qq.com

    最近我们环境从复)星(云切换到阿里云.早上地铁路上就有小伙伴@,一阵搜索.找的如下的方法. 记录一下: 目前只支持安卓手机的微信内置浏览器清理. 由腾讯提供的网址http://debugx5.qq.c ...

  8. vagrant网站中box下载方法

    假设需要下载Laravel/homestead这个包. 首先定位到地址:https://app.vagrantup.com/laravel/boxes/homestead/versions/8.0.0 ...

  9. 2019/10/9 CSP-S 模拟测

    T1:最大约数和 给定一个正整数 S,现在要求你选出若干个互不相同的正整数,使得它们的和不大于 S,而且每个数的因数(不包括本身)之和最大.S <= 1000 分析: 其实考完才听他们说是背包, ...

  10. JS全局函数里面的一些区别