Gym101466I DP 记忆化搜索
从前往后扫,对于既可以去A班,又可以去B班的人进行决策。
状态设计有两种姿势。
第一种姿势比较暴力&玄学:用dp[x][2][y][2]
记录下,A班最后一位同学的id,这位同学有没有id比他更小的朋友。对B班也一样. 数组开不下,所以我们可以使用unordered map
,但很不幸,这么做会MLE成智障,我们可以加一个小优化:发现了一个解后,直接结束输出Yes。
code
#include <iostream>
#include <vector>
#include <unordered_map>
using namespace std;
const int N=100000+10;
int n,k,a[N],s[N];
bool chk1(int x) {
vector<int> v;
while(x) v.push_back(x%10), x/=10;
for(int i=0;i<v.size();i++)
if (v[i] != v[v.size()-1-i])
return 0;
return 1;
}
bool chk2(int x) {
while(x) {
if(x%10!=4&&x%10!=7) return 0;
x/=10;
}
return 1;
}
unordered_map<int,int> mp[100000+10][2][2];
int dfs(int x,int y,int cx,int cy,int cur) {
//printf("%d %d %d %d %d\n", x,y,cx,cy,cur);
if (cur == n+1) {
bool ok=0;
if (cx == 1 && y == 0) ok=1;
if (cy == 1 && x == 0) ok=1;
if (cx == 1 && cy == 1) ok = 1;
if (ok) {
printf("Yes\n");
exit(0);
}
return ok;
}
if (mp[x][cx][cy].count(y))
return mp[x][cx][cy][y];
int ret = 0;
if (s[cur] & 1) {
if (x == 0) {
ret = max(ret, dfs(cur,y,0,cy,cur+1));
} else {
if (cur-x<=k)
ret = max(ret, dfs(cur,y,1,cy,cur+1));
else {
if (cx == 1)
ret = max(ret, dfs(cur,y,0,cy,cur+1));
}
}
}
if (s[cur] & 2) {
if (y == 0) {
ret = max(ret, dfs(x,cur,cx,0,cur+1));
} else {
if (cur-y<=k)
ret = max(ret, dfs(x,cur,cx,1,cur+1));
else {
if (cy == 1)
ret = max(ret, dfs(x,cur,cx,0,cur+1));
}
}
}
return mp[x][cx][cy][y] = ret;
}
int main() {
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++) {
scanf("%d",&a[i]);
if (chk1(a[i])) s[i]|=1;
if (chk2(a[i])) s[i]|=2;
if (s[i]==0) return !printf("No\n");
}
printf("%s\n", dfs(0,0,0,0,1)?"Yes":"No");
}
但是,我们应该相信珂学的!
我们不妨这么来设计状态:用dp[now][x][y][cx][cy]
表示,now位置之前考虑好了,现在在施展now位置。
1)x: now与上一个A班孩子的距离
2)y: now与上一个B班孩子的距离。
注: 当距离大于20时,是没有区别的,所以把大于20的距离都看成21就好了
3)cx: 上一个A班的孩子有没有朋友
4)cy: 上一个B班的孩子有没有朋友。
#include <iostream>
#include <vector>
#include <unordered_map>
#include <bitset>
using namespace std;
const int N=100000+10;
bitset<N> vis[22][22][3][3],dp[22][22][3][3];
int n,k,a[N],s[N];
bool chk1(int x) {
vector<int> v;
while(x) v.push_back(x%10), x/=10;
for(int i=0;i<v.size();i++)
if (v[i] != v[v.size()-1-i])
return 0;
return 1;
}
bool chk2(int x) {
while(x) {
if(x%10!=4&&x%10!=7) return 0;
x/=10;
}
return 1;
}
int dfs(int now,int dx,int dy,int cx,int cy) {
//printf("%d %d %d %d %d\n",now,dx,dy,cx,cy);
if (now == n+1) {
if (cx==0||cy==0) return 0;
return 1;
}
if(vis[dx][dy][cx][cy][now]) {
return dp[dx][dy][cx][cy][now];
}
bool ret = 0; vis[dx][dy][cx][cy][now] = 1;
if (s[now]&1) {
if (dx==k+1&&cx==0){}
else ret|=dfs(now+1,1,min(dy+1,k+1),dx<=k?1:0,cy);
}
if (s[now]&2) {
if (dy==k+1&&cy==0) {}
else ret|=dfs(now+1,min(dx+1,k+1),1,cx,dy<=k?1:0);
}
return dp[dx][dy][cx][cy][now]=ret;
}
int main() {
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++) {
scanf("%d",&a[i]);
if (chk1(a[i])) s[i]|=1;
if (chk2(a[i])) s[i]|=2;
if (s[i]==0) return !printf("No\n");
}
printf("%s\n", dfs(1,k+1,k+1,1,1)?"Yes":"No");
}