其他分享
首页 > 其他分享> > CF(6.7-6.8)(从IOI到ACM)

CF(6.7-6.8)(从IOI到ACM)

作者:互联网

G

  简单叙述一下吧:类似 散步 那道题,只不过要用线段树维护不能上暴力。简单说一下线段树的思想,维护区间速度的最值,因为在左边的速度最大——维护一个不上升的序列;

  Sakura_Lu现在的马蜂还行,去看他的应该能看懂。link

 

F(Shifting String) 

    *Polycarp 找到了字符串 s 和排列 p。结果证明它们的长度相同并且等于 n。

    *n 个元素的排列 — 是一个长度为 n 的数组,其中从 1 到 n 的每个整数恰好出现一次。例如,[1,2,3] 和 [4,3,5,1,2] 是排列,但是 [1,2,4], [4,3,2,1,2] 和 [0,1 ,2] 不是。

    *在一次操作中,他可以将 s 与 p 相乘,因此他将 s 替换为字符串 new,其中对于从 1 到 n 的任何 i,newi=s*pi

    *例如,当 s=wmbe 和 p=[3,1,4,2] 时,操作后字符串会变成   s=s3s1s4s2=bwem。

    *Polycarp 想知道在经过多少次操作后,该字符串将首次等于其初始值。

输入样例:

3
5
ababa
3 4 5 2 1
5
ababa
2 1 4 5 3
10
codeforces
8 6 1 7 5 2 9 3 10 4

 输出样例:

1
6
12

    大体思路:不难想到给这些字母建边(有枪战Maf)的感觉,这些字母最终就会构成一个个的环,我们将这些环找出来,发现最终的答案就是这些环(字符串)的最小循环节长度的最小公倍数。

    所以代码分为两部分:1)找环DFS、2)求最小循环节长度KMP(蓝书有讲P74)

Code moo~~

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<string>
#define Bessie moo~~
#define int long long
using namespace std;
int read(){
    int A=0,fl=1;
    char C=getchar();
    while(C<'0'||C>'9')fl= C=='-' ? -1 : 1, C=getchar();
    while(C>='0'&&C<='9')A=(A<<3)+(A<<1)+(C^48),C=getchar();
    return A*fl;
}
int T,n,ans,tot;
int a[305],vis[305];
char ch[305],ch2[305];
void dfs(int x){
    vis[x]=1;
    ch2[tot++]=ch[x];
    if(!vis[a[x]])dfs(a[x]);
}
int nxt[305];
void getnxt(int l){
    memset(nxt,0,sizeof(nxt));
    for(int i=2,j=0;ch2[i];i++){
        while(j>0&&ch2[i]!=ch2[j+1])j=nxt[j];
        if(ch2[i]==ch2[j+1])j++;
        nxt[i]=j;
    }
}
int gcd(int x,int y){
    if(y==0)return x;
    return gcd(y,x%y);
}
int lcm(int x,int y){
    return x*y/gcd(x,y);
}
signed main(){
    T=read();
    while(T--){
        n=read();
        memset(vis,0,sizeof(vis));
        ans=1;
        for(int i=0;i<n;i++){
            cin>>ch[i];
        }
        for(int i=0;i<n;i++){
            a[i]=read();
            a[i]--;
        }
        for(int i=0;i<n;i++){
            if(!vis[i]){
                tot=1;
                dfs(i);
                // printf("%s",ch2);
                // for(int j=0;j<tot;j++)printf("%c",ch2[j]);
                getnxt(tot);
                // printf("%s",ch2);
                tot--;
                if(tot%(tot-nxt[tot])!=0){
                    // printf(" %lld\n",tot);
                    ans=lcm(ans,tot);
                }
                else {
                    // printf(" %lld\n",(tot-nxt[tot]));
                    ans=lcm(ans,tot-nxt[tot]);
                }
            }
        }
        printf("%lld\n",ans);
        // printf("\n\n");
    }
    return 0;
}

 

 

 

  后记:第一次在机房通宵,越打越兴奋,比赛结束后感觉根本不困,并且学到了线段树更灵活的用法,以及KMP求循环元的方法。

  ······吐槽一句:机房的蚊子把我的胳膊咬了5个指甲盖大小的包······

标签:return,int,CF,ACM,6.7,read,ch2,字符串,include
来源: https://www.cnblogs.com/Creator-157/p/16355199.html