F. Shifting String #797div3
题意是给你一个字符串和一个排列,s1s2s3s4...变成sp1,sp2,sp3...
比如abcd 4 2 1 3=>dbac
问你至少操作多少次可以变成原来的字符串
这题一看就是周期问题,然后我直接上手暴力,不出意外的tle了hh
不要那么一根筋啊,要多想想的
仔细揣摩可以发现 如果像是ab 21的话,会一直变成ba ab...这样子循环,那这对循环与其他字母怎么循环无关,这样命名一下为一个环。然后整个序列里面可以找到若干个这样的环,不管怎么循环,它们循环自己的与其他无关。这样的话,整个序列的周期就是所有环的lcm(最小公倍数)
注意一点:环的长度!=这个环的周期 刚开始我怎么也没想出来
把环求出来还需要求一下这个环的周期
周期怎么求:最长不可能超过这个环的长度,因为最坏的情况是全部循环一遍,直接上个公式吧:s[(a+k)%cnt]==s[a]如果每个字母都可以满足这个条件,说明循环一遍之后还是它,从小到大枚举满足条件的就是最小周期
周期还有一种求法,一位大佬提醒用kmp可以把时间复杂度优化到O(n),我不会QAQ...
(其实还有一种方法,我不会映射而已...QAQ)
#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
#define IOS ios::sync_with_stdio(false), cin.tie(0);
#include<iostream>
#include<map>
#include<set>
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
#include<cmath>
#include<queue>
#include<deque>
using namespace std;
typedef long long ll;
typedef pair<int,int> PAII;
const int N=2e6+10,M=5050,INF=0x3f3f3f3f,mod=998244353;
int read()
{
int x = 0, f = 1;
char c = getchar();
while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x * f;
}
int p[N];
bool st[N];
char ch[N],s[N];
int main(){
IOS;
int T;
//T=1;
cin>>T;
while(T--)
{
int n;
cin>>n;
cin>>ch+1;
for(int i=1;i<=n;i++)
{
cin>>p[i];
st[i]=false;
}
ll res=1;
for(int i=1;i<=n;i++)
{
if(!st[i])
{
int cnt=0;
for(int j=i;!st[j];st[j]=true,j=p[j]) s[cnt++]=ch[j];//找到环**
ll t;
for(int k=1;k<=cnt;k++)//找周期 周期最多是长度
{
if(cnt%k==0)
{
int f=1;
for(int z=0;z<cnt;z++)
{
if(s[(z+k)%cnt]!=s[z])
{
f=0;
break;
}
}
if(f)
{
t=k;
break;
}
}
}
res=res/__gcd(t,res)*t;
}
}
cout<<res<<"\n";
}
return 0;
}
/*
*/
多积累题目经验吧.
******************************************************
题意是给你一个排列a,一个排列b,给一个序列c,如果c等于0,从ai或者bi任意选一个数 保证ci一定为ai bi中的任意一个,问有多少种这样的方案,要保证c是个排列
这个题也是和环有关的,予以并查集进行实现
因为你会发现 如果有一个值你知道了,接下来的一连串的数你可能都确定了
所以这就是个突破口
可以把ab序列划分成若干个环,环的性质是只要你确定了其中的任何一个数,那整个环的其他数字你全都知道了。所以在找到环的时候,你还需要判断一下这个环里面有没有确定的数字,如果有,那很好,这个环的贡献是1,(其实由于乘法原理,这个1是乘的1可以不用管),如果没有,那这个环的贡献就是2,很好证,其实就是一个位置有两种选择,每选一种其他数字都确定进而全部的环的选择也就是贡献为2。但是这里注意一下,如果某个环的长度是1,那贡献也是1
#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
#define IOS ios::sync_with_stdio(false), cin.tie(0);
#include<iostream>
#include<map>
#include<set>
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
#include<cmath>
#include<queue>
#include<deque>
using namespace std;
typedef long long ll;
typedef pair<int,int> PAII;
const int N=2e6+10,M=5050,INF=0x3f3f3f3f,mod=1e9+7;
int a[N],b[N],c[N],p[N];
bool st[N],s[N];
int main(){
//IOS;
int T;
//T=1;
cin>>T;
while(T--)
{
int n;
cin>>n;
for(int i=1;i<=n;i++) st[i]=false,s[i]=false;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=n;i++) cin>>b[i];
for(int i=1;i<=n;i++)
{
cin>>c[i];
if(c[i])
{
st[a[i]]=true;
st[b[i]]=true;
}
}
for(int i=1;i<=n;i++) p[a[i]]=b[i];
ll res=1;
for(int i=1;i<=n;i++)
{
if(!s[i])
{
int f=0,cnt=0;
for(int j=i;!s[j];j=p[j])
{
s[j]=true;
cnt++;
f=f|st[j];
}
if(cnt!=1&&!f) res=res*2%mod;
}
}
cout<<res<<"\n";
}
return 0;
}
/*
*/