洛谷P10361 [PA 2024] Łamigłówka 3
给出一种朴素(暴力)做法
题面分析
给出的一个 \(n \times m\) 的目标网格图。每次操作能使一行或一列变为一种颜色,需要你构造一种在 \(n + m\) 次操作之内,将空图变成目标图的方案。
发现:每次操作后必有至少一行或一列为同一种颜色,相反地,我们也能从目标图每次找只有一种颜色的一行或一列来反推步骤。
关于具体实现
具体地,每次找到只有一种颜色的一行或一列抹除,抹除后这些格子的颜色可能为所有颜色,反着记录答案。
这个东西的时间复杂度明显是不对的,但是我们有一个优化方案:
- 当所有行或者所有列都被抹除过显然已经还原成空图。
但时间复杂度仍然不对粗略估计有 \(O(n^3)\)。
但是由于我们每次遍历时可以改变多个行和列,实际耗时远不及理论复杂度。
到这里测试下来只有一个点过不了。
再加上本题的大量输入输出,进行输入输出优化后可以过最后一个点。
Code
#include<bits/stdc++.h>
using namespace std;
#define ll long long
int rd()//快读
const int N = 2005;
int n,m,cnt;
int mp[N][N];
struct node
{
char a,c;
int b;
}a[N + N];
bool vis[N + N];
int num1,num2;
signed main()
{
n = rd(),m = rd();
for(int i = 1;i <= n;i++)
{
for(int j = 1;j <= m;j++)
{
char c = getchar();
mp[i][j] = c - 'A';
}
getchar();
}
for(int i = 1;i <= n + m;i++)
{
for(int j = 1;j <= n;j++)
{
if(vis[j]) continue;
bool f = 1;
int x = -1;
for(int k = 1;k <= m;k++) if(mp[j][k] != -1)
{
x = mp[j][k];
break;
}
for(int k = 1;k <= m;k++) if(mp[j][k] != x && mp[j][k] != -1)
{
f = 0;
break;
}
if(f)
{
num1++;
vis[j] = 1;
int c = -1;
for(int k = 1;k <= m;k++) if(mp[j][k] != -1) c = mp[j][k],mp[j][k] = -1;
if(c == -1) continue;
a[++cnt].a = 'R';
a[cnt].b = j;
a[cnt].c = (char)(c + 'A');
}
}
for(int j = 1;j <= m;j++)
{
if(vis[j + n]) continue;
bool f = 1;
int x = -1;
for(int k = 1;k <= n;k++) if(mp[k][j] != -1)
{
x = mp[k][j];
break;
}
for(int k = 1;k <= n;k++) if(mp[k][j] != x && mp[k][j] != -1)
{
f = 0;
break;
}
if(f)
{
num2++;
vis[j + n] = 1;
int c = -1;
for(int k = 1;k <= n;k++) if(mp[k][j] != -1) c = mp[k][j],mp[k][j] = -1;
if(c == -1) continue;
a[++cnt].a = 'K';
a[cnt].b = j;
a[cnt].c = (char)(c + 'A');
}
}
if(num1 == n || num2 == m) break;
}
cout << cnt << '\n';
for(int i = cnt;i >= 1;i--) cout << a[i].a << ' ' << a[i].b << ' ' << a[i].c << '\n';
return 0;
}

浙公网安备 33010602011771号