题解:P17872 [FJCPC 2026] 限号出行
题目传送门
思路
先把字符转为数字。
接着可以用 dp 判断可行性。
设
那么我们只需检查满足
转移的话,首先显然
然后定义两个变量
限制的话用个桶记录就行了,注意清空。
字典序的话由于
代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e5+5,inf=1e18;
int T,n,m,k,f[N][27];
int mp[127][127],fl,cnt;
int now,pos[N][27];
string s,a;
int t[N];
char x,y;
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>T;
while(T--)
{
cin>>n>>m>>k>>a;
for(int i=0;i<n;i++) t[i]=a[i]-'a'+1;//转数字
for(int i=1;i<=26;i++)
{
for(int j=1;j<=26;j++) mp[i][j]=0;//清空桶
}
for(int i=0;i<=n;i++)
{
for(int j=1;j<=26;j++)
{
pos[i][j]=inf;//清空预处理数组
f[i][j]=0;//清空dp结果
}
}
pos[n-1][t[n-1]]=n;
for(int i=n-2;i>=0;i--)
{
for(int j=1;j<=26;j++) pos[i][j]=pos[i+1][j];
pos[i][t[i]]=i+1;
}//预处理
for(int i=1;i<=m;i++)
{
cin>>x>>y;
mp[x-'a'+1][y-'a'+1]=1;//标记
}
f[n][t[n-1]]=1;//初始化
for(int i=n-1;i>=1;i--)
{
f[i][t[i-1]]=1;
for(int j=1;j<=26;j++) f[i][j]=max(f[i+1][j],f[i][j]);
for(int k1=1;k1<=26;k1++) if(!mp[t[i-1]][k1]) f[i][t[i-1]]=max(f[i][t[i-1]],f[i+1][k1]+1);
}//转移
fl=0;
for(int i=1;i<=26;i++)
{
if(f[1][i]>=k) fl=1;
}
if(!fl)
{
cout<<"-1\n";
continue;
}//判可行性
now=0;
s="A";//一开始塞一个特殊字符
cnt=0;
while(cnt<k)
{
for(int j=1;j<=26;j++)
{
if(f[now+1][j]>=k-cnt&&!mp[s[cnt]-'a'+1][j])
{
s+=char(j-1+'a');
cnt++;
now=pos[now][j];
break;
}
}
}
s.erase(0,1);//最后再删掉特殊字符
cout<<s<<'\n';//模拟选的过程
}
return 0;
}