@codeforces - 1205C@ Palindromic Paths
@description@
这是一道交互题。
现在有一个 n*n 的矩阵,每个位置是 0 或 1。现在已知 n 为奇数、左上角为 1、右下角为 0。
你可以向交互库给出询问 "? x1 y1 x2 y2",交互库会回答是否存在一条路径从 (x1, y1) 出发仅往右或往下走到达 (x2, y2),且路径上所有数拼起来形成回文串。如果存在为 1,否则为 0。
请注意询问时必须保证 x1 <= x2, y1 <= y2 且 (x2 - x1) + (y2 - y1) > 1,即 (x1, y1) 在 (x2, y2) 的左上方,且它们不能相邻。
请使用不超过 n^2 组询问,还原出这个矩阵。
Input
第一行包含一个奇数 n (3 <= n < 50)。
Interaction
你可以按照格式 "? x1 y1 x2 y2" 给出询问,含义如上。
当你决定好了矩阵中的所有元素,请输出一行 "!",紧接着输出你的矩阵。
Example
Input
3
0
1
0
1
1
1
1
Output
? 1 1 1 3
? 1 1 2 3
? 2 1 2 3
? 3 1 3 3
? 2 2 3 3
? 1 2 3 2
? 1 2 3 3
!
100
001
000
@solution@
考虑一个长度为 3 的询问,实际上 是不是回文串 只跟 开头与末尾是否相同 有关。
于是将矩阵黑白染色后,可以通过若干长度为 3 的询问得到黑格之间的相对关系,白格之间的相对关系。这个可以用带权并查集。
因为是相对关系,所以 n^2 个点只询问 n^2 - 1 次询问,实际上因为已经给定左上与右下,所以实际还会少一点点。
我们假设左上角为黑格,则所有黑格的数字都已经可以确定。
我们接下来就是尝试找到 1 个询问,使我们可以确定某个白格的数字,这样总询问次数也不会超过上界。
考虑一个 2*3 的子矩形,询问左上角的 (x, y) 到右下角的 (x + 1, y + 2)(同理可以推到 3*2 上面去)。
因为是 2*3,所以 (x, y) 与 (x + 1, y + 2) 必然有一个黑格,不失一般性设 (x, y) 为黑格。
假如 (x + 1, y + 2) 填充与 (x, y) 不同,必然没有回文串;否则假如填充相同时一定存在回文串,我们就可以通过这个询问确定白格。
讨论几种情况:
(1)假如 (x + 1, y + 1) ≠ (x, y + 2),则路径 (x, y) -> (x, y + 1) -> (x, y + 2) -> (x + 1, y + 2) 与 (x, y) -> (x, y + 1) -> (x + 1, y + 1) -> (x + 1, y + 2) 中必然有一个回文串。
(2)假如 (x + 1, y) ≠ (x, y + 1),则同理可得路径 (x, y) -> (x + 1, y) -> (x + 1, y + 1) -> (x + 1, y + 2) 与 (x, y) -> (x, y + 1) -> (x + 1, y + 1) -> (x + 1, y + 2) 中必然有一个回文串。
(3)假如上述两种情况对于任意子矩形都不满足,等价于所有 左上 - 右下 的对角线上的数全部相同。
这时候考虑,假如 (x, y) = (x + 1, y + 1) 与 (x + 1, y + 2) = (x, y + 1) 同时满足或者同时不满足,则也必然存在一个回文串。
否则当 (x + 1, y + 2) ≠ (x, y + 1) 时,(x, y) 所在对角线与 (x + 1, y + 1) 所在对角线相同;又因以 (x, y + 1) 为左上角时,又可以推出 (x + 1, y + 1) 与 (x + 2, y + 2) 所在对角线相同。进一步推出所有黑格对角线相同,然而这与左上角为 1 右下角为 0 矛盾。
当 (x + 1, y + 2) = (x, y + 1),大概就是所有黑格对角线形成 10101... 这样间隔开来的形式。然而因为 n 为奇数,所以有奇数条黑格对角线,于是这又与左上角为 1 右下角为 0 矛盾。
综上,以上 3 种情况必然有一个成立,这个算法可以找出解。
@accepted code@
#include<cstdio>
int query(int x1, int y1, int x2, int y2) {
printf("? %d %d %d %d\n", x1, y1, x2, y2);
fflush(stdout);
int x; scanf("%d", &x);
return x;
}
int num[50 + 5][50 + 5], n;
int fa[50*50 + 5], f[50*50 + 5];
int find(int x) {
if( fa[x] == x ) return x;
int y = fa[x]; fa[x] = find(fa[x]);
f[x] ^= f[y];
return fa[x];
}
void link(int x, int y, int k) {
int fx = find(x), fy = find(y);
fa[fx] = fy, f[fx] = f[x]^f[y]^k;
}
int d[50*50 + 5];
int main() {
scanf("%d", &n);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
num[i][j] = (i - 1)*n + j;
for(int i=1;i<=n*n;i++)
fa[i] = i, f[i] = 0;
link(num[1][1], num[2][2], !query(1, 1, 2, 2));
for(int i=3;i<=n;i+=2)
link(num[1][i], num[1][i-2], !query(1, i-2, 1, i));
for(int i=4;i<=n;i+=2)
link(num[2][i], num[2][i-2], !query(2, i-2, 2, i));
for(int i=4;i<=n;i+=2)
for(int j=2;j<=n;j+=2)
link(num[i-2][j], num[i][j], !query(i-2, j, i, j));
for(int j=1;j<=n;j+=2)
for(int i=3;i<=n;i+=2)
link(num[i-2][j], num[i][j], !query(i-2, j, i, j));
link(num[2][1], num[3][2], !query(2, 1, 3, 2));
for(int i=3;i<=n;i+=2) {
link(num[i-2][2], num[i][2], !query(i-2, 2, i, 2));
link(num[2][i-2], num[2][i], !query(2, i-2, 2, i));
}
for(int i=4;i<=n;i+=2)
for(int j=1;j<=n;j+=2) {
link(num[i-2][j], num[i][j], !query(i-2, j, i, j));
link(num[j][i-2], num[j][i], !query(j, i-2, j, i));
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
find(num[i][j]);
for(int i=1;i+2<=n;i++) {
for(int j=1;j+1<=n;j++) {
if( (f[num[i][j]] == f[num[i+2][j]]) == (f[num[i+1][j]] == f[num[i+2][j+1]]) || f[num[i+1][j]] != f[num[i][j+1]] || f[num[i+2][j]] != f[num[i+1][j+1]] ) {
if( (i+j) & 1 ) d[fa[num[i][j]]] = f[num[i+2][j+1]]^(!query(i, j, i+2, j+1))^f[num[i][j]];
else d[fa[num[i+2][j+1]]] = f[num[i][j]]^(!query(i, j, i+2, j+1))^f[num[i+2][j+1]];
puts("!");
for(int i=1;i<=n;i++) {
for(int j=1;j<=n;j++)
printf("%d", d[fa[num[i][j]]]^f[num[i][j]]);
puts("");
}
return 0;
}
if( (f[num[j][i]] == f[num[j][i+2]]) == (f[num[j][i+1]] == f[num[j+1][i+2]]) || f[num[j][i+1]] != f[num[j+1][i]] || f[num[j][i+2]] != f[num[j+1][i+1]] ) {
if( (i+j) & 1 )
d[fa[num[j][i]]] = f[num[j+1][i+2]]^(!query(j, i, j+1, i+2))^f[num[j][i]];
else
d[fa[num[j+1][i+2]]] = f[num[j][i]]^(!query(j, i, j+1, i+2))^f[num[j+1][i+2]];
puts("!");
for(int i=1;i<=n;i++) {
for(int j=1;j<=n;j++)
printf("%d", d[fa[num[i][j]]]^f[num[i][j]]);
puts("");
}
return 0;
}
}
}
}
@details@
因为时间不够我也没仔细研究官方给出的构造方法,不过构造方法据我了解也比较多。
像这种构造题主要还是从小的数据范围考虑起,把复杂问题简单化吧。
@codeforces - 1205C@ Palindromic Paths的更多相关文章
- Codeforces 1205C Palindromic Paths (交互题、DP)
题目链接 http://codeforces.com/contest/1205/problem/C 题解 菜鸡永远做着变巨的梦 然而依然连div1BC题都不会做 要是那天去打cf怕是又要1题滚粗了.. ...
- Educational Codeforces Round 89 (Rated for Div. 2) C Palindromic Paths
题目链接:Palindromic Paths 题意: 给你一个n行m列的矩阵,这个矩阵被0或者1所填充,你需要从点(1,1)走到点(n,m).这个时候会有很多路径,每一条路径对应一个01串,你可以改变 ...
- [USACO15OPEN]回文的路径Palindromic Paths
[USACO15OPEN]回文的路径Palindromic Paths 题目描述 Farmer John's farm is in the shape of an N \times NN×N grid ...
- TOJ 5020: Palindromic Paths
5020: Palindromic Paths Time Limit(Common/Java):10000MS/30000MS Memory Limit:65536KByteTotal Su ...
- 题解 P3126 【[USACO15OPEN]回文的路径Palindromic Paths】
P3126 [USACO15OPEN]回文的路径Palindromic Paths 看到这题题解不多,蒟蒻便想更加通俗易懂地分享一点自己的心得,欢迎大佬批评指正^_^ 像这种棋盘形的两边同时做的dp还 ...
- CodeForces 835D - Palindromic characteristics | Codeforces Round #427 (Div. 2)
证明在Tutorial的评论版里 /* CodeForces 835D - Palindromic characteristics [ 分析,DP ] | Codeforces Round #427 ...
- Educational Codeforces Round 89 (Rated for Div. 2) C. Palindromic Paths(贪心)
题目链接:https://codeforces.com/contest/1366/problem/C 题意 有一个 $n \times m$ 的 $01$迷宫,要使从 $(1,1)$ 到 $(n,m) ...
- Educational Codeforces Round 89 (Rated for Div. 2) C. Palindromic Paths (思维)
题意:有一个\(n\)x\(m\)的矩阵,从\((1,1)\)出发走到\((n,m)\),问最少修改多少个数,使得所有路径上的数对应相等(e.g:\((1,2)\)和\((n-1,m)\)或\((2, ...
- [USACO15OPEN]回文的路径Palindromic Paths 2.0版
题目描述 农夫FJ的农场是一个N*N的正方形矩阵(2\le N\le 5002≤N≤500),每一块用一个字母作标记.比如说: ABCD BXZX CDXB WCBA 某一天,FJ从农场的左上角走到右 ...
随机推荐
- java并发系列(二)-----线程之间的协作(wait、notify、join、CountDownLatch、CyclicBarrier)
在java中,线程之间的切换是由操作系统说了算的,操作系统会给每个线程分配一个时间片,在时间片到期之后,线程让出cpu资源,由其他线程一起抢夺,那么如果开发想自己去在一定程度上(因为没办法100%控制 ...
- Jeecms网站直接访问html静态页面
jeecms网站维护,遇到了直接通过链接的方式访问静态页面,jeecms官网也做了详细的解答,但是没有得到满意的结果.但是通过自己的深入研究以及别人的帮助,发现了一个很好的解决方法. 首先说明一下je ...
- angular和vue的对比学习之路
vue-ng 打开vue的中文官网一段关于vue的描述 HTML 模板 + JSON 数据,再创建一个 Vue 实例,就这么简单. 那我么再看下angular中文网 AngularJS是为了克服HTM ...
- 学习Python笔记---操作列表
1.for循环: 编写for循环时,对于用语存储列表中每个值的临时变量,可指定任何名称. 在for循环中,想包含多少行代码都可以,每个缩进的代码行都是循环的一部分,且将针对列表中的每个值都执行一次. ...
- php 抽奖概率算法
lottery.php <?php //转自https://segmentfault.com/a/1190000007431893 /* * 不同概率的抽奖原理就是把0到*(比重总数)的区间分块 ...
- hdu 1358 Period(KMP入门题)
Period Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Subm ...
- 安装docker报错问题
安装docker容易出现错误的几种情况: 1.网络问题,无法下载完成的docker容器 2.linux内核版本必须是3.10及以上 3.可以选择使用aliyun的yum源,更好用 4.
- eNSP模拟器路由器无法正常启动一直显示“#”——问题解决方法
eNSP模拟器路由器无法正常启动一直显示“#” 问题项如截图: 解决方案: 1. 打开自己电脑的控制面板 -->> 系统和安全 -->> Windows Defender防火墙 ...
- vue 根据数组中某一项的值进行排序
一.前言 我在vue项目中遇到了一个表格排序的需求,根据某一项的值的大小从大到小调整数组顺序. 二.代码 表格大概是这个样子,样式和图片在代码中简化了. <table class="r ...
- VisualTreeHelper使用——使用BFS实现高效率的视觉对象搜索
BFS,即广度优先搜索,是一种典型的图论算法.BFS算法与DFS(深度优先搜索)算法相对应,都是寻找图论中寻路的常用算法,两者的实现各有优点. 其中DFS算法常用递归实现,也就是常见的一条路找到黑再找 ...