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
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- 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
- {
- if(s[(z+k)%cnt]!=s[z])
- {
- f=0;
- break;
- }
- }
- if(f)
- {
- t=k;
- break;
- }
- }
- }
- res=res/__gcd(t,res)*t;
- }
- }
- cout<
"\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
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- 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<
"\n"; - }
- return 0;
- }
- /*
- */