link
CCF 目前在 CSP-J 出过的唯一蓝题,也是个 nggyu 题。
题目大意
n 个人进行接龙游戏,每人有一个长为 \(l_i\) 的序列 \(S_i\)。
规则
-
接龙起始序列为 \(\{1\}\)。
-
每轮进行接龙的人不能是上一轮的人。
-
当前玩家在自己的序列中选出一个满足接龙条件的连续子序列。
-
选出的子序列长度必须在 [2,k] 范围内,k 是定值。
有 q 次询问,每次询问给出 \(r_i\ ,c_i\)
求恰好进行 \(r_i\) 轮接龙的情况下,是否存在一种情况,使最终接龙序列的末位字符为 \(c_i\),存在输出 1,不存在输出 0。
正解
奶龙题就懒得说部分分了,直接考虑 dp。
状态设计
考虑设计一个二维 dp [ i ] [ j ] ,表示接龙序列末位字符为 j 时可以进行第 i 轮接龙的玩家,如果有多位就用 0 表示,所以初始值全部设为 -1。
看一眼题目范围发现时间空间都卡的刚刚好,且询问时可 O(1) 回答,所以这就是正解😋。
状态转移
应该是个人就会。
第一层枚举进行轮数,很明显每一轮都由上一轮转移来。
第二层枚举每个玩家序列的字符更新答案,直接将上一轮满足条件的末尾字符作为这一轮的起始点,往后扫 k 个打上标记,遇到打过标记的就直接给它置为 0(表示有多个玩家满足条件)。
求完 dp 数组之后直接 O(1) 回答询问即可。
AC代码
#include <bits/stdc++.h> using namespace std; const int maxn=2e5+9; const int maxm=109; int T,n,k,q,r,c; int tail[maxm][maxn]; vector<int> S[maxn]; int main(){ scanf("%d",&T); while(T--){ scanf("%d%d%d",&n,&k,&q); for(int i=1,l;i<=n;i++){ scanf("%d",&l);S[i].clear(); for(int j=1,x;j<=l;j++){ scanf("%d",&x); S[i].push_back(x); } } memset(tail,-1,sizeof tail),tail[0][1]=0; for(r=1;r<=100;r++){ for(int i=1;i<=n;i++){ int len=0; for(auto x:S[i]){ if(len) len--; if(len){ if(tail[r][x]==-1) tail[r][x]=i; else if(tail[r][x]^i) tail[r][x]=0; } if(~tail[r-1][x]&&tail[r-1][x]^i) len=k; } } } while(q--){ scanf("%d%d",&r,&c); puts(~tail[r][c]?"1":"0"); } } return 0; }
干脆改名叫接奶龙得了。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!