首页 > 其他分享 > CF1205C Palindromic Paths 题解

CF1205C Palindromic Paths 题解

时间:2023-06-16 21:22:23浏览次数:36  
标签:Paths 两种 return int 题解 询问 CF1205C 情况 我们

很好的一道题,思路自然,步骤清晰,结论好猜。唯一的缺点可能只是我赛时没有看到。


构造可行解

看到题目,也许我们很快就能想出一个做法:每次询问 \((i,j,i+1,j)\),每行第一个额外询问 \((i,j,i+1,j)\),这样询问总共 \(n ^ 2 - 1\) 次即可。

当我们怀疑看错题目重新检查时发现了被微软翻译漏掉的条件:\(x_1+y_1+2 \le x_2 + y_2\)。

长度为 \(2\) 不行,我们可以长度为 \(3\)。每次询问 \((i,j,i,j + 2)\),每行第一个额外询问 \((i,j,i + 2,j)\),第一行第一个额外询问 \((1,1,2,2)\),偶数行的 \(i\) 从 \(2\) 开始。

由于我们已知点 \((1,1)\) 为 \(1\),这样相当于往棋盘上染成国际象棋的黑白两色。不妨设点 \((1,1)\) 为黑色,那么我们知道黑色的棋子的确切值。

a[1][1] = 1;
a[n][n] = 0;
for (int x = 1; x <= n; ++x) {
  int p = (x & 1 == 1 ? 1 : 2);
  if (x <= n - 2) {
    cout << "? " << x << ' ' << p << ' ' << x + 2 << ' ' << p << endl;
    a[x + 2][p] = a[x][p] ^ (!read());
  }
    
  for (int y = p; y <= n - 2; y += 2) {
    if (y == n - 2 && x == n) break;// 最后一个格子已知,没必要求
    cout << "? " << x << ' ' << y << ' ' << x << ' ' << y + 2 << endl;
    a[x][y + 2] = a[x][y] ^ (!read());
  }
    
  if (x == 1 && x < n) {
    cout << "? " << x << ' ' << p << ' ' << x + 1 << ' ' << p + 1 << endl;
    a[x + 1][p + 1] = a[x][p] ^ (!read());
  }
}

我们不知道白色格子的确切值,但是我们可以知道白色格子的相对值。也就是我们假设点 \((1,2)\) 为 \(1\),那么我们可以求出所有白色格子的值。方法与上类似,这里不再赘述。

b[1][2] = 1;
for (int x = 1; x <= n; x += 2) {
  for (int y = 2; y <= n - 1; y += 2) {
    if (y < n - 1) {
	  cout << "? " << x << ' ' << y << ' ' << x << ' ' << y + 2 << endl;
	  ++cnt;
	  b[x][y + 2] = b[x][y] ^ (!read());	
    }
    if (x < n) {
	  cout << "? " << x << ' ' << y << ' ' << x + 1 << ' ' << y + 1 << endl;
	  b[x + 1][y + 1] = b[x][y] ^ (!read());	
    }
  }
  if (x < n) {
    cout << "? " << x << ' ' << 2 << ' ' << x + 2 << ' ' << 2 << endl;
    b[x + 2][2] = b[x][2] ^ (!read());
    cout << "? " << x + 1 << ' ' << 1 << ' ' << x + 2 << ' ' << 2 << endl;
    b[x + 1][1] = b[x + 2][2] ^ (!read());	  
  }
}

现在唯一的问题是,点 \((1,2)\) 既有可能为 \(1\),也有可能为 \(0\)。我们需要判断两种方案哪一种是正确的。在之前的过程中我们对除了 \((1,1),(1,2),(n,n)\) 三个点之外的所有点进行了一次判断,也就是说我们还剩下 \(3\) 次询问。

判断正确性

既然所有长度为 \(3\) 的路径都被我们考虑过了,我们顺理成章地考虑长度为 \(4\) 的路线。需要注意的是,我们的解法不能与 \((i,j,i,j + 3)\) 这样的询问有关,因为当 \(n = 3\) 时这是一个非法询问(为什么更长长度的路线不考虑?也是思考 \(n=3\) 的情况可以把它们全部排除)。

也就是说,我们应该的询问类似于 \((i,j,i + 2,j + 1)\)。由于这样的询问在给出否定答案时只能揭露点值的关系,无法给出具体信息,所以我们的判定方法只能是一种方案这个询问为真,另一种方案这个询问为假。在 \((n - 2) \times (n - 1)\) 个矩阵中找出一个满足条件的矩阵进行验证即可。

有没有可能这样的矩阵不存在?我们来分类讨论一下。

两种方案均为真

这种情况不存在。因为 \((i,j)\) 必定不和 \((i + 2,j + 1)\) 同色(对颜色的定义参照构造可行解一节),所以两种方案中有且仅有一个点发生改变,所以必定在一种情况里 \((i,j) = (i + 2,j + 1)\),在另一种情况中 \((i,j) \neq (i + 2, j + 1)\)。

两种情况均为假

一种情况为假有两种可能:

  1. 两端点不同。
  2. 路径中间上的两个点不同。

所有路径中央的两个点必然属于异色,所以在一种情况不同时,另一种情况必然相同。因此两种方案必定分别属于上面的两种可能。所以这种情况只可能是下面的形式:

第一种:

11 10
10 00
01 00

第二种:

10 11
01 11
11 10

由于我们希望所有 \((i,j,i + 2,j + 1)\) 的询问答案均为假,所以我们必须把矩阵补全。但是我们发现了两点:

  1. 这两种情况互斥,出现了第一种情况就不可能出现第二种情况。

如果 \(n=3\),有一个看似成功的补全:

110
101
011

但这样 \((n,n) = 1\),不符合题目条件。

否则如果两个连续的 \(1\) 不出现在最后,就必定会有一个矩形不存在于两种情况之间,不符合我们的条件。

  1. 单一的情况不能补全矩形。

原因是我们不可能出现多个连续的 \(1\) 的同时还保证每个 \(1\) 下面的数都为一样的数。

因此,这种情况不可能存在。

于是我们找到一个两种方案矛盾的矩形进行询问,选择符合条件的那边即可。总共用了 \(n^2 - 2\) 次询问,超额完成任务。

代码实现

#include<iostream>
#include<algorithm>

using namespace std;

const int N = 55;s

int read() {
  int x;cin >> x;return x;
}

struct mar {
  int a[4][3];
  bool check() {
    if (a[1][1] != a[3][2]) return false;
    if (a[1][2] == a[2][2]) return true;
    if (a[2][1] == a[2][2]) return true;
    if (a[2][1] == a[3][1]) return true;
    return false;
  }
};

int n;
int a[N][N], b[N][N];

int main() {
  ios::sync_with_stdio(false);
  cin.tie(0);
  cout.tie(0);

  cin >> n;
  for (int x = 1; x <= n; ++x) {
    for (int y = 1; y <= n; ++y) {
      a[x][y] = -1;
    }
  }
  a[1][1] = 1;
  a[n][n] = 0;
  for (int x = 1; x <= n; ++x) {
    int p = (x & 1 == 1 ? 1 : 2);
    if (x <= n - 2) {
      cout << "? " << x << ' ' << p << ' ' << x + 2 << ' ' << p << endl;
      a[x + 2][p] = a[x][p] ^ (!read());
    }
    
    for (int y = p; y <= n - 2; y += 2) {
      if (y == n - 2 && x == n) break;
      cout << "? " << x << ' ' << y << ' ' << x << ' ' << y + 2 << endl;
      a[x][y + 2] = a[x][y] ^ (!read());
    }
    
    if (x == 1 && x < n) {
      cout << "? " << x << ' ' << p << ' ' << x + 1 << ' ' << p + 1 << endl;
      a[x + 1][p + 1] = a[x][p] ^ (!read());
    }
  }

  
  for (int i = 1; i <= n; ++i) {
    for (int j = 1; j <= n; ++j) {
      b[i][j] = -1;
    }
  }
  b[1][2] = 1;
  for (int x = 1; x <= n; x += 2) {
    for (int y = 2; y <= n - 1; y += 2) {
      if (y < n - 1) {
        cout << "? " << x << ' ' << y << ' ' << x << ' ' << y + 2 << endl;
        b[x][y + 2] = b[x][y] ^ (!read());	
      }
      if (x < n) {
        cout << "? " << x << ' ' << y << ' ' << x + 1 << ' ' << y + 1 << endl;
        b[x + 1][y + 1] = b[x][y] ^ (!read());	
      }
    }
    if (x < n) {
      cout << "? " << x << ' ' << 2 << ' ' << x + 2 << ' ' << 2 << endl;
      b[x + 2][2] = b[x][2] ^ (!read());

      cout << "? " << x + 1 << ' ' << 1 << ' ' << x + 2 << ' ' << 2 << endl;
      b[x + 1][1] = b[x + 2][2] ^ (!read());	
      
    }
  }
  // we find a and b

  mar z, f;
  int chk = 0, pd = 0;
  for (int i = 1; i <= n - 2; ++i) {
    for (int j = 1; j <= n - 1; ++j) {
      for (int x = i, wx = 1; x <= i + 2; ++x, ++wx) {
        for (int y = j, wy = 1; y <= j + 1; ++y, ++wy) {
        if (a[x][y] == -1) z.a[wx][wy] = b[x][y];
        else z.a[wx][wy] = a[x][y];
        }
      }
      for (int x = i, wx = 1; x <= i + 2; ++x, ++wx) {
        for (int y = j, wy = 1; y <= j + 1; ++y, ++wy) {
        if (a[x][y] == -1) f.a[wx][wy] = !b[x][y];
        else f.a[wx][wy] = a[x][y];
        }
      }
      if (z.check() != f.check()) {
        cout << "? " << i << ' ' << j << ' ' << i + 2 << ' ' << j + 1 << endl;
        int tmp = read();
        if (tmp == f.check()) chk = 1;
        pd = 1;
        break;
      }
    }
    if (pd == 1) break;
  }

  cout << "!" << endl;
  for (int i = 1; i <= n; ++i) {
    for (int j = 1; j <= n; ++j) {
      if (a[i][j] != -1) cout << a[i][j];
      else cout << (b[i][j] ^ chk);
    }
    cout << endl;
  }

  return 0;	
}

标签:Paths,两种,return,int,题解,询问,CF1205C,情况,我们
From: https://www.cnblogs.com/closureshop/p/CF1205C.html

相关文章

  • 「ULSG-1」泡水的铅筒 题解
    题目传送门题目描述一个圆锥放入一个长方体水池中,无水溢出,求长方体液面高度的最大、最小值。解题思路如果这个题只有一个数据点,此数据点只有一组数据,那这就是一道初中填空题()先考虑\(h1\)的最小值。由“铅筒被完全浸没且没有液体溢出水池外”一句可得,若圆锥放入水池后液面高......
  • 「ULSG-1」2048 题解
    题目传送门题目解析玩一次就明白了。传送门解题思路合并从下往上,从左往右,对于每一个非零的数,向上第一个非零数,若与之相等,则此数与找到的数相加,同时分数加上合并后的数,而找到的数清零。若第一个非零数与它不相等,直接停止寻找过程,意为无法合并,等待下落。下落依旧从下往上,从......
  • 「ULSG-1」数字生命 题解
    题目传送门题目描述给定一段长度为\(n\)的序列,找出其中长度为\(m\)的一段子序列,且其中各数字出现次数与给定模板中相对应的次数不相同的数字等于\(k\)。题目解法容易联想到一个用于求固定长度区间最大值的\(O(n)\)算法——「滑动窗口」,此题可借鉴此算法。我们以此题的......
  • 「SiR-1」Checkmate 题解
    题外话:本体题目出自番剧《NOGAMENOLIFE》且题目背景中来吧,游戏开始了。是第一季中男主“空”的口头禅。(强烈推荐观看《NOGAMENOLIFEZERO》)回归正题awaP9355「SiR-1」Checkmate题解题目传送门博客宣传题目解读:在\(n\)行\(m\)列的棋盘中放置多枚棋子,求出其上......
  • 【BZOJ 3156】防御准备 题解
    原题令\(S_{i}=\sum_{j=1}^{i}j\),\(f_{i}\)为处理到第\(i\)个位置放置守卫塔的最小花费。观察题意,容易得到在\((1<=j<=i-1)\)时,有\(f_{i}=min\left\{f_{j}+\sum_{k=j+1}^{i-1}(i-k)+a_{i}\right\}\)①\(f_{i}=min\left\{f_{j}+\sum_{k=j+1}^{i-1}(i-k)\ri......
  • Linux中-bash: /dev/null: Permission denied问题解决
    云上架构2021年08月06日09:19 ·  阅读682​今天在Centos7上运行如下命令 shell复制代码######添加hdfs用户#####useraddhdfs######切换至hdfs用户#####su-hdfs报如下错误 javascript复制代码-bash:/dev/null:Permissiondenied-bash......
  • [ABC114D] 756 题解
    题目链接题意给定一个数\(n\),求\(n!\)的因数中,刚好有\(75\)个因数的数的个数。分析首先有这样一个性质,对于一个数\(a\),我们将其分解质因数,即\[a=\prod_{i=1}^{n}p_i^{k_i}\]那么,\(a\)的因数个数就是\[sum=\prod_{i=1}^{n}(k_i+1)\]简单证明一下,对于第......
  • Alien 的排列题解
    Description求出有多少\(2\simn+1\)的排列\(\{P_{n}\}\),使得对于所有\(1\leqi\leqn\)有\(i|P_{i}\)。对于\(30\%\)的数据\(n\leq10\)。对于\(90\%\)的数据\(n\leq3000\)。对于\(100\%\)的数据\(n\leq10^9\)。Solution如果把\(n+1\)固定在第\(1\)个......
  • 问题解决sql文件上传和蚁剑连接
    1.无法连接上自己的ip:发现问题是上传的木马不在127.0.0.1的文件下时,会导致解析不到木马,要将木马上传到127.0.0.1的文件下连接2.解决sql上传一句话木马问题要先在mysql的配置文件my.ini中添加导入导出数据库的地址:secure_file_priv=D:\phpstudy_pro\WWW然后重启数据库,可以进行sq......
  • [ZJOI2022] 深搜 题解
    题目描述九条可怜是一个喜欢算法的女孩子,在众多算法中她尤其喜欢深度优先搜索(DFS)。有一天,可怜得到了一棵有根树,树根为\(\mathit{root}\),树上每个节点\(x\)有一个权值\(a_x\)。在一棵树上从\(x\)出发,寻找\(y\)节点,如果使用深度优先搜索,则可描述为以下演算过程:将递归栈......