标签:前缀 pos can 开始 strlen 思维 不能 puts define
感觉这一题的状态设计很有讲究
一开始的思路是枚举s的前半部分,去贪心的匹配t串,然后再看剩余部分是否可以匹配t的后半部分
但这种思路显然是错的(样例都过不了),原因是可能t后半部分的某个特征串只在s中(对应的一个特征序列)出现了一次,
但是这个s中的特征序列由于被t前半部分贪心的匹配,被打破了,所以不能成功匹配后半部分
后来想到枚举t的前半部分和后半部分,然后用一个二维dp[i][j]去枚举匹配即可
/* 枚举pos:1->T,表示t被分成t[1..pos]和t[pos+1..T]两个串 dp[i][j]表示 t1匹配到i位,t2匹配到j位的最短的s前缀 */ #include<bits/stdc++.h> using namespace std; #define N 405 char s[N],t[N]; int S,T,dp[N][N],nxt[N][26],pos[26]; void init(){ for(int i=0;i<26;i++)pos[i]=S+1; for(int i=S;i>=0;i--){ for(int j=0;j<26;j++) nxt[i][j]=pos[j]; if(i)pos[s[i]-‘a‘]=i; } } char t1[N],t2[N]; int len1,len2; int solve(int pos){ for(int i=0;i<=T;i++) for(int j=0;j<=T;j++) dp[i][j]=0x3f3f3f3f; len1=pos,len2=T-pos; for(int i=1;i<=len1;i++)t1[i]=t[i]; for(int i=1;i<=len2;i++)t2[i]=t[i+pos]; dp[0][0]=0; for(int i=0;i<=len1;i++) for(int j=0;j<=len2;j++){ if(i==0 && j==0)continue; if(i){ int last=dp[i-1][j]; if(last<=S) dp[i][j]=min(dp[i][j],nxt[last][t1[i]-‘a‘]); } if(j){ int last=dp[i][j-1]; if(last<=S) dp[i][j]=min(dp[i][j],nxt[last][t2[j]-‘a‘]); } } if(dp[len1][len2]<=S)return 1; return 0; } int main(){ int tt;cin>>tt; while(tt--){ scanf("%s%s",s+1,t+1); S=strlen(s+1); T=strlen(t+1); init(); int flag=0; for(int i=1;i<=T;i++) if(solve(i))flag=1; if(flag)puts("YES"); else puts("NO"); } }
标签:前缀 pos can 开始 strlen 思维 不能 puts define
原文地址:https://www.cnblogs.com/zsben991126/p/12311230.html