Problem - C - Codeforces
题意是给你一个2*n的网格,让你一笔把所有的B涂满,并且只能涂一次,问你是否可行
分析:
其实分析的时候我想到了转移。每一次的结果是由上一次转移而来,所以如果前后矛盾的话,即不成立,可以分析出来有三种情况:
第一种:某一列全是B,那不管前一列怎么转移过来,上面的必然要走到下面,下面的必然要走一下上面,所以再往前推一格。两种情况,如果从上面走到下面,那上面是由i-1转移过来,同理下面
第二种:某一列有一个B,那就是由同一行的前一列所转移过来
第三种是第二种的另外一个情况,某一列的另外一个B
其实赛时的时候,这个我都看出来了,(也不难想)
但是不知道怎么去实现
可以用动态规划呀(动态规划记录路径)
从刚开始的开头赋值为1,进行转移。每一层的状态由它理论转移位置去进行转移,最后看看最后一列的B的位置上是否把开头的1转移过来。
其实这题可以很好的理解动态规划的状态转移的思想
令为第i列的第一行和第i列的第二行的转移状态。
最后看看 或者是否有1
下面看代码:
#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
#define IOS ios::sync_with_stdio(false), cin.tie(0);
#include<iostream>
#include<map>
#include<set>
#include<cstdio>
#include<cstring>
#include<vector>
#include<stack>
#include<algorithm>
#include<cmath>
#include<queue>
#include<deque>
using namespace std;
#define int long long
typedef long long ll;
typedef pair<int,int> PAII;
const int N=2e6+10,M=5050,INF=1e18,mod=998244353;
char ch[5][N];
int f[N][5],a[5][N];
signed main(){
//IOS;
int T;
//T=1;
cin>>T;
while(T--)
{
int n;
cin>>n;
for(int i=1;i<=2;i++)
for(int j=1;j<=n;j++)
{
cin>>ch[i][j];
if(ch[i][j]=='B') a[i][j]=1;
else a[i][j]=0;
}
int minn=n+1,maxn=-1,ff=0;
for(int i=1;i<=n;i++)
{
f[i][1]=0;
f[i][2]=0;
if(a[1][i]||a[2][i])
{
ff=1;
minn=min(minn,i);
maxn=max(maxn,i);
}
}
if(ff==0)
{
cout<<"YES\n";
continue;
}
f[minn][1]=(a[1][minn]==1);
f[minn][2]=(a[2][minn]==1);
for(int i=minn+1;i<=maxn;i++)
{
if(a[1][i]==1&&a[2][i]==1)
{
f[i][1]=f[i-1][2];
f[i][2]=f[i-1][1];
}
if(a[1][i]==1&&a[2][i]==0) f[i][1]=f[i-1][1];
if(a[1][i]==0&&a[2][i]==1) f[i][2]=f[i-1][2];
}
if(f[maxn][1]||f[maxn][2]) cout<<"YES\n";
else cout<<"NO\n";
}
return 0;
}
/*
令f[i][1/2]为第i列的上面和下面分别可不可以走到
*/