本文最后更新于 125 天前,其中的信息可能已经有所发展或是发生改变。
读题!
每次选择长度从 2 到 k 的若干个连续的数字接龙。第一个人从1开始接,其余正常接。
每次询问要求恰好接龙 r_j 次,最后一次接龙的最后一个数字恰好是 c_j,问能不能做到。
让我想想怎么做?
首先很容易想到用DFS暴力枚举每一种情况,看看是否可行。
但是此时的时间复杂度为 O(\sum l q) !!太大啦!!!
所以每次询问只能用 O(1) 的时间复杂度。
既然每次询问只能用 O(1) 的时间复杂度,那么我们就可以考虑预处理。
每次询问有给定的 r_j 和 c_j,而r \leq 100、c \leq 2e5,所以我们可以考虑预处理出 f_{r,j} 表示第 r 轮时,能不能以数字 j 结尾(能的话记是谁接的)。
它有三种取值:
     -1:不能以 j 结尾
     i:表示是第 i 个人在第 r 轮接到 j
     0:表示不仅仅是一个人,多个不同的人都可以在第 r 轮接到 j(后续可由任意人接)
从第 r−1 轮转移到第 r 轮,我们只关心:
某个数 u 如果出现在第 r−1 轮的结尾,并且不是 i 这个人接的,那么在第 i 人的词库中,以 u 开头的长度在 [2,k] 的连续子串,这些子串的结尾数字,就可以成为第 r 轮的候选。
上代码!
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define foru(a,b,c) for(ll a=b;a<=c;a++)
ll t,f[105][200005];
void real_mian();
int main(){
    cin>>t;
    while(t--) real_mian();//真正的mian函数
    return 0;
}
void real_mian(){
    ll n,k,q,x,y;
    cin>>n>>k>>q;
    vector<vector<ll>>a(n+5);
    foru(i,1,n){
        cin>>x;
        a[i].clear();//记得清空
        foru(j,1,x){
            cin>>y;
            a[i].push_back(y);
        }
    }
    foru(i,0,100){
        foru(j,0,200000){
            f[i][j]=-1;//初始化
        }
    }
    f[0][1]=0;//第一次接龙从1开始
    foru(i,1,100){//枚举第几轮
        foru(j,1,n){//枚举每个人
            ll cnt=0;//记录还能接几个数
            for(auto x:a[j]){//枚举每个人的词库
                if(cnt>0){//还能接
                    if(f[i][x]==-1){//没人接(这是第一次接)
                        f[i][x]=j;//默认只能j接
                    }else if(f[i][x]!=j){//不是第一次接,且不是j接
                        f[i][x]=0;//那就随便接了
                    }
                    cnt--;//还能接龙的数量-1
                }
                if(f[i-1][x]!=-1&&f[i-1][x]!=j){//上一轮能接上,并且不是j接的
                    cnt=k-1;//这一轮还能接k-1个
                }
            }
        }
    }
    foru(i,1,q){
        cin>>x>>y;
        cout<<(f[x][y]==-1?0:1)<<endl;//直接输出
    }
}