题意
给定n个长度为m的字符串,和一个长度为m的字符串s,将s分为
k个互不相交且长度大于1的子串,如果能分割,输出k行,每行
3个整数l,r,i代表第i个字符串的l--r的下标,如果不能,输出-1.
解题思路
由于题目没有要求结果分解出来的字串个数最少,那么就可以
将目标字符串分解成若干个长度为2或3的子串,并在预处理时
提前标记好n个字符串所有长度为2或3的子串,这样就可以得出
状态转移方程dp[i]=dp[i-2]或dp[i]=dp[i-3],只要dp[i-2]=1且这
个长度为2的字串出现过,那么dp[i]=1,处理完后,看看dp[m]
是否等于1即可.
代码
#include<bits/stdc++.h>
using namespace std;
int t,n,k,ff[10][10],fff[10][10][10],dp[1005],ans[1005];
string s,ss;
struct node{
int l,r,ii;
}anss[1005];
int main(){
cin>>t;
while(t--){
memset(ff,0,sizeof(ff));
memset(fff,0,sizeof(fff));
memset(dp,0,sizeof(dp));
memset(ans,0,sizeof(ans));
cin>>n>>k;
for(int i=1;i<=n;++i){
cin>>s;
int len=s.size();
for(int j=0;j<len-1;++j){
int h=s[j]-48;
int hh=s[j+1]-48;
ff[h][hh]=(i-1)*k+j+1;
}
for(int j=0;j<len-2;++j){
int h=s[j]-48;
int hh=s[j+1]-48;
int hhh=s[j+2]-48;
fff[h][hh][hhh]=(i-1)*k+j+1;
}
}
cin>>ss;
dp[0]=1;
dp[1]=0;
for(int i=2;i<=k;++i){
if(i==2){
if(ff[ss[i-2]-48][ss[i-1]-48]!=0&&dp[i-2]==1){
dp[i]=1;
ans[i]=i-2;
}
}
else{
int h=ss[i-3]-48;
int hh=ss[i-2]-48;
int hhh=ss[i-1]-48;
if(ff[hh][hhh]!=0&&dp[i-2]==1){
dp[i]=1;
ans[i]=i-2;
}
if(fff[h][hh][hhh]!=0&&dp[i-3]==1){
dp[i]=1;
ans[i]=i-3;
}
}
}
if(dp[k]==0){
cout<<"-1\n";
}
else{
int t=k,cnt=0;
while(t>1){
if(ans[t]==t-2){
int h=ss[t-2]-48;
int hh=ss[t-1]-48;
int p=ff[h][hh];
cnt++;
anss[cnt].l=(p-1)%k+1;
anss[cnt].r=(p-1)%k+2;
anss[cnt].ii=(p-1)/k+1;
t-=2;
}
else{
int h=ss[t-3]-48;
int hh=ss[t-2]-48;
int hhh=ss[t-1]-48;
int p=fff[h][hh][hhh];
cnt++;
anss[cnt].l=(p-1)%k+1;
anss[cnt].r=(p-1)%k+3;
anss[cnt].ii=(p-1)/k+1;
t-=3;
}
}
cout<<cnt<<"\n";
for(int i=cnt;i>=1;--i){
cout<<anss[i].l<<" "<<anss[i].r<<" "<<anss[i].ii<<"\n";
}
}
}
return 0;
}