cf1690F. Shifting String(div3)

传送门

题意

给定一个长度为 n 的字符串和数组 p,字符串的每次变换都将以数组 p 中的数字作为基准,问在经过最少几次(不可以为 0 0 0 )变换后,该字符串能够变换为与初始字符串相同。

请添加图片描述

对样例 3 手模后,可以得到如上表格(眼瞎了,可能有错,凑合看看规律 ),发现其中是以若干个环进行滚动的,如下标 ( 1 , 8 , 3 ) , ( 2 , 6 ) , ( 4 , 7 , 9 , 10 ) , ( 5 ) (1,8,3),(2,6),(4,7,9,10),(5) 1,8,32,6,4,7,9,10,5 ,在最坏情况下求出每个环的长度的最小公倍数即为操作次数。

然而环中可能存在相同字符的情况,使得操作次数可以在该环的长度以内即可完成一次循环,特判该情况即可。

#include <bits/stdc++.h>
#define int long long
using namespace std;

const int N=210;
int p[N],vis[N];

int lcm(int a,int b){
	return a/__gcd(a,b)*b;
}

void solve(){
    int n;
    string s;
	cin>>n>>s;
	memset(vis,0,sizeof(vis));
	for(int i=0;i<n;i++)
		cin>>p[i],p[i]--;

	int ans=1;
	for(int i=0;i<n;i++){
        if(vis[i])
            continue;
        int j=i;
		string x="";
		while(!vis[j]){//当前环
			x+=s[j];
			vis[j]=1;
			j=p[j];
		}

		int len=x.size(),minn=len;

		for(int i=1;i*i<=len;i++){
			if(len%i==0){
				bool flag=1;
				for(int j=0;j<i&&flag;j++)
					for(int k=j;k<len&&flag;k+=i)
						flag&=(x[j]==x[k]);
				if(flag)
					minn=min(minn,i);
                //cout<<"flag="<<flag<<" minn="<<minn<<endl;
				if(i*i<len){
					bool ok=1;
					for(int j=0;j<len/i&&ok;j++)
						for(int k=j;k<len&&ok;k+=len/i)
							ok&=(x[j]==x[k]);
					if(ok)
						minn=min(minn,len/i);
                    //cout<<"ok=="<<ok<<" minn="<<minn<<endl;
				}
                
			}
        }
		ans=lcm(ans,minn);
    }
	cout<<ans<<endl;
}
signed main(){
	ios::sync_with_stdio(false),cin.tie(nullptr);
	int T;
	cin>>T;
	while(T--)
		solve();
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值