题解:P11230 [CSP-J 2024] 接龙(民间数据)

· · 题解

动态规划题。

dp_{i,j} 表示第 j 轮时数字 i 能否被转移。其中 dp_{i,j}=-1 表示不能,

每次转移将每个人扫一遍,用 x 来维护当前是否有可以转移的状态,特判前一个状态和这个状态是否为同一个人即可。 upd:发现不用快读,优化了一下码风。 ```cpp #include<bits/stdc++.h> using namespace std; int T,n,k,q,l[200010],xx[200010],yy[200010],dp[200010][110]; vector<int>v[200010];//每个人的词库 int main() { ios::sync_with_stdio(0); cin>>T; while(T--){ cin>>n>>k>>q; int maxl=0,maxr=0; for(int i=1;i<=n;i++){ cin>>l[i]; v[i].clear(); for(int j=1;j<=l[i];j++){ int x; cin>>x; maxl=max(maxl,x); v[i].push_back(x); } } for(int i=1;i<=q;i++){ cin>>xx[i]>>yy[i]; maxr=max(maxr,xx[i]); } for(int i=0;i<=maxl;i++){ for(int j=0;j<=maxr;j++){ dp[i][j]=-1; } } dp[1][0]=0;//必须从1开始 for(int i=1;i<=maxr;i++){//i为轮数 for(int j=1;j<=n;j++){ int x=-1; for(int k1=0;k1<v[j].size();k1++){ int t1=v[j][k1];//t1为这个人的第k1+1个单词 if(k1>=k){//长度超过k int t2=v[j][k1-k]; if(dp[t2][i-1]!=-1&&dp[t2][i-1]!=j&&x==k1-k)x=-1;//如果唯一能转移的状态出界 } if(x!=-1){//更新当前状态 if(dp[t1][i]==-1)dp[t1][i]=j; else if(dp[t1][i]!=j)dp[t1][i]=0; } if(dp[t1][i-1]!=-1&&dp[t1][i-1]!=j)x=k1;//更新x } } } for(int i=1;i<=q;i++){ if(yy[i]>maxl)cout<<"0";//如果不存在yy[i] else cout<<(dp[yy[i]][xx[i]]!=-1);//否则输出是否无解 cout<<"\n"; } } } ```