2024csp-jT4接龙题

题目描述:
总共有 n 个人参与这个接龙游戏,第 i 个人会获得一个整数序列Si作为他的词库。
一次游戏分为若干轮,每一轮规则如下:
n 个人中的某个人 p 带着他的词库 Sp进行接龙。若这不是游戏的第一轮,那么这一轮进行接龙的人不能与上一轮相同,但可以与上上轮或更往前的轮相同。
接龙的人选择一个长度在 [2,k] 的 sp的连续子序列 A 作为这一轮的接龙序列,其中 k 是给定的常数。若这是游戏的第一轮,那么 A 需要以元素 1 开头,否则 A 需要以上一轮的接龙序列的最后一个元素开头。
序列 A 是序列 S 的连续子序列当且仅当可以通过删除 S 的开头和结尾的若干元素(可以不删除)得到 A。
为了强调合作,小 J 给了 n 个参与游戏的人 q 个任务,第 j 个任务需要这 n 个人进行一次游戏,在这次游戏里进行恰好 rj轮接龙,且最后一轮的接龙序列的最后一个元素恰好为 cj。为了保证任务的可行性,小 J 请来你判断这 q 个任务是否可以完成的,即是否存在一个可能的游戏过程满足任务条件。

思路:
一、暴力分治法
我们可以对每个对象的序列便利找到从起点S开始的后k-1个字符E作为终点,并判断S-E是否是以1作为起点以C作为终点的其中一部分。特别的若接龙次数r只有1次,直接找从起点S开始找,若碰到终点判断距离是否小于K。

二、分治法
从1开始不断接龙,可以考虑成类似于对所有对象的序列进行图的广度搜索,不过每次搜索的过程都是将所有对象的序列重新便利一遍。每次搜索都是找到起点S之后将起点之后的K-1个值进行存储,在下次搜索的过程中以这些值为起点。但是需要考虑的是上一次接龙对象这一次不能再次接龙,因此我们需要存储每次终点属于哪个对象,如果某个终点属于多个对象,就用特殊值标记。注意若某个终点属于多个对象中的序列,实际在下一次搜索中每个对象都可以搜索。为此我们可以定义一个dp二维数组,第一位表示接龙次数,第二位表示终点(类似于桶标记),其值的含义表示终点来自于哪个对象,若来自多个对象则以-1表示。二维数组dp[i][j]表示的含义是第i次接龙以j为终点的接龙是否存在。
`#include <bits/stdc++.h>
using namespace std;

typedef struct node{
int startv;
int form;
}Node;
int sto[200005];
int m[105][200005];
int sp[100005];
int n,k,q;
int r,c;
int cnt;

void getDp()
{
memset(m,0,sizeof(m));
m[0][1]=-1;
for(int i=1;i<=100;i++)
//进行r次接龙
{
for(int v=1;v<=n;v++)
//从n个对象中遍历
{
int len=0;
for(int j=sp[v-1];j<sp[v];j++)
//判断sto[j]这个值是否可以作为起点,<类似于用m[v-1][sto[j]]实现标记>
{
if(len>0)
{
if(m[i][sto[j]]!=0&&m[i][sto[j]]!=v)
m[i][sto[j]]=-1;
else
m[i][sto[j]]=v;
len--;
}
if(m[i-1][sto[j]]!=0&&m[i-1][sto[j]]!=v)
len=k-1;
}
}
}

}

int main()
{
int T;
cin>>T;
for(int i=1;i<=T;i++)
{
cnt=0;
cin>>n>>k>>q;
sp[0]=0;
int len;
for(int j=1;j<=n;j++)
{
cin>>len;
sp[j]=sp[j-1]+len;
for(;cnt<sp[j];cnt++)
cin>>sto[cnt];
}
getDp();
for(int j=0;j<q;j++)
{
cin>>r>>c;
if(m[r][c]!=0)
cout<<1<<endl;
else
cout<<0<<endl;
}
}
}`

时间复杂度:O(T100∑Li)

posted @   jenniferCAI  阅读(106)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示