竟然是青题,我想了两个小时...
我真的不知道这道题该怎么快速想到思路,因为按照中间的那个点来选还是太神了。如果有能更快想到的方法希望能指出。
我看到这道题,第一反应是感觉思路挺多的。
首先肯定是先手搓看一下有没有规律。
我找了 发现规律全是错的,只有 的时候直接贪心是对的。
二分图/网络流很容易想到,但是复杂度...还是算了。但过程中我们容易发现这道题的一个比较关键的性质:一个点最多有两种可能的组成方法。
然后去想 dp,发现没有办法进行 的大小的转移,这个思路好像也进行不下去。
于是就在草稿纸上一直画。会画出类似这种的图案(用数字代替字母):
1
123 12
123 123
123 23
3
1
1
123
23
3
比如这几个,我们需要找找有没有规律.
我们看最下面那一个,可以发现,我们如果以中间那个为枚举的基准,可能是很有前途的,然后我们可以发现一些性质(有用的 feihua):
-
一个中心点可以经过一个横着的和竖着的。
-
能够相互影响的只有斜着的,按照枚举顺序在当前点之前的只有右上角那一个。能影响到的也只有左下角那一个。
然后就可以推出有用的结论:
- 一个点能不能横着/竖着有自身,和右上角是横着/竖着决定。
然后就可以想到,我们可以记录下当前点能否横着/竖着,然后该怎么放就让左下角的点决定。
于是就能写出来类似 dp 的贪心代码。
我感觉考后的思路会比考试时候的思路稍微清晰一点。反正这道题做起来真的有点看“灵机一动”。
看看我考场怎么挂的 :
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,m;
char a[3010][3010],b[3010][3010];
bool ok[3010][3010][2];
signed main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
//freopen 正确
cin>>n>>m;
for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)cin>>a[i][j],b[i][j]=a[i][j];
n=m=max(n,m);
int ans=0;
if(n<=4&&m<=4){
for(int i=1;i<=n;i++){
for(int j=1;j+2<=n;j++)if(a[j][i]=='R'&&a[j+1][i]=='G'&&a[j+2][i]=='W'){
a[j][i]=a[j+1][i]=a[j+2][i]='/';
ans++;
}
for(int j=1;j+2<=n;j++)if((a[i][j]=='R'&&a[i][j+1]=='G'&&a[i][j+2]=='W')){
a[i][j]=a[i][j+1]=a[i][j+2]='/';
ans++;
}
}
for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)a[i][j]=b[i][j];
cout<<ans<<endl;
// return 0;
}
ans=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(a[i][j]!='G')continue;
if(a[i][j-1]=='R'&&a[i][j+1]=='W')ok[i][j][0]=1;
if(a[i-1][j]=='R'&&a[i+1][j]=='W')ok[i][j][1]=1;
if(ok[i-1][j+1][1]==1&&ok[i-1][j+1][0]==0){
ok[i][j][0]=0;
}
if(ok[i-1][j+1][0]==1&&ok[i-1][j+1][1]==0){
ok[i][j][1]=0;
}
if(ok[i][j][0]||ok[i][j][1])ans++;
}
}
cout<<ans<<endl;
return 0;
}
/*
首先我们可以先把用了一定不会更劣的情况用了
第一列和第一行可以直接用掉
然后第二行和第二列,这种顺序感觉没有问题
nm 不同就取 max 不影响答案
感觉像 dp,但是我又不会转移,这玩意儿有上下两种
哦,这样是错的
暴力一点,把所有的 RGW 弄出来,网络流,这样显然会 TLE
这个图有一个性质,一个点最多在两个 RGW 上面
然后我们可以尝试中间点 G?
就是每一种直接匹配中间点 G,
嗯,这道题既然没有让输出方案数,会不会有更直接的结论?
重合一个答案少 1
先写一下。
cao,这个结论显然是错的
我觉得这道题可以用神经网络做...只是我不会而已
因为这道题神经网络可以训练出来比较优秀的数据,然后应该可以过
但正解肯定不是了
等等,如果按照刚刚的匹配中心点,那么从上往下贪心匹配一定是可以的吧
也就是按照第二个的遍历到的顺序为优先级?
这样的话可以证明,横着和竖着都只有一个冲突的,也就是我们可以记录他是否可以横着/竖着
*/