AtCoder Regular Contest 154 C. Roller(思维题)

题目

T(T<=5e3)组样例,每次给定一个数n(n<=5e3),

和长为n的两个数组a,b,你可以执行以下操作任意次:

操作:选择一个下标i(1<=i<=n),将a_{i}替换为a_{i+1},其中a_{n+1}被认为是a_{1}

问若干次操作后,a和b能否完全相同,可以输出Yes,不能输出No

思路来源

灵茶群

题解

注意到需要初始局面至少有一个元素相等,

所以本能的想法是枚举初始点,然后往前或往后暴力赋值,

赋ai的时候,只考虑ai原来的值、ai+1原来的值,ai+1后来被赋的值

但是,这个做法是假的,赛中会一直ac26wa34,

考虑以下样例,相同的数字段,实际是可以循环移位,越过原来的位置的

6
1 1 1 2 1 3
1 3 2 2 2 2

根据能平移,衍生成了题解的做法:

将a和b分别看成环,并尺取相同值的段去重,得到新的数组a'和b'

1. b'的长度为n,说明a'的长度也得为n,且和原来的元素一一对应

2. b'长度小于n,说明b的总种类数小于n,说明a最终总种类数小于n即可,

则a'至少可以执行一次操作,覆盖掉一个元素,有一个空位后,则可以执行循环移位操作,

比如,1123->1223->1233->2311

支持了这样的循环移位后,只需要b’是a'循环移位条件下的子序列即可

因为a'支持两种操作,一种是循环移位,另一种是赋值覆盖,覆盖掉不想要的元素种类

代码

#include<iostream>
#include<vector>
using namespace std;
const int N=5e3+10,mod=998244353;
int T,n,c[N],d[N];
vector<int>a,b;
void calc(int *x,vector<int>&y){
    y.clear();
    int las=-1;
    for(int i=0;i<n;++i){
        cin>>x[i];
        if(x[i]!=las)y.push_back(x[i]);
        las=x[i];
    }
    if(y.size()>1 && y.back()==y[0])y.pop_back();
}
bool solve(){
    int sa=a.size(),sb=b.size();
    if(sb==n)return a==b;
    for(int i=0;i<sa;++i){
        int cur=0;
        for(int j=0;j<sa;++j){
            if(b[cur]==a[(i+j)%sa])cur++;
            if(cur==sb)return 1;
        }
    }
    return 0;
}
int main(){
    cin>>T;
    while(T--){
        cin>>n;
        calc(c,a);calc(d,b);
        cout<<(solve()?"Yes":"No")<<endl;
    }
    return 0;
}
/*
2
4
1 1 2 3
2 3 3 3
6
1 1 1 2 1 3
1 3 2 2 2 2
*/

猜你喜欢

转载自blog.csdn.net/Code92007/article/details/128761910