• NOIP 模拟 929


    匹配

    有两个字符串A,B,其中B是A的一个长度为$l_{B}$前缀,现在给B末尾填上字符,求A的最大前缀等于B的后缀

    $T<=10,l_{B}<=100000,l_{B}<=l_{A}<=2*l_{B}$,所有字母均为小写字母

    题解

    考虑到B除了最后一个字符就是A的前缀,所以如果变换后的B不是A的前缀,那么求B的最大前缀等于后缀即可。

    用kmp就行了

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    
    const int maxn=200005;
    int T,lena,lenb;
    char c[2],s[maxn],t[maxn];
    int fail[maxn];
    void kmp(){
        fail[0]=fail[1]=0;
        for(int i=1;i<lenb;i++){
            int t=fail[i];
            while(t&&s[i]!=s[t]) t=fail[t];
            fail[i+1]=(s[i]==s[t] ? t+1 : 0);
        }
    }
    
    int main(){
        freopen("string.in","r",stdin);
        freopen("string.out","w",stdout);
        scanf("%d",&T);
        while(T--){
            scanf("%d%d%s%s",&lena,&lenb,s,c);
            if(s[lenb]==c[0]) {printf("%d
    ",lenb+1);continue;}
            s[lenb++]=c[0];
            kmp();
            printf("%d
    ",fail[lenb]);
        }
    }
    string

    回家

    有一个n个点m条边的图,求从1到n的必经点。

    m<=2n,n<=200000,多组数据

    题解

    给一种错误思路:考虑必经点一定是割点,必经点一定在最短路上。所以tarjan求出割点之后,跑两遍bfs求最短路,最后判断。

    为什么会错呢?因为这些只是性质,并不能推出结论。

    最主要的就是不能保证这个割点能使1和n不连通

    所以考虑在tarjan的时候记录n是否在子树中,判断即可。

    细节在代码注释

    #include<queue>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    
    const int maxn=200005;
    const int inf=0x3f3f3f;
    int t,n,m,cur,cnt;
    int head[maxn];
    int dfn[maxn],low[maxn];
    int top,sta[maxn];
    bool cut[maxn],con[maxn];
    int dis[maxn][2];
    struct edge{
        int x,y,next;
    }e[maxn<<3];
    
    template<class T>inline void read(T &x){
        x=0;int f=0;char ch=getchar();
        while(!isdigit(ch)) {f|=(ch=='-');ch=getchar();}
        while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
        x = f ? -x : x ;
    }
    
    void add(int x,int y){
        e[++cnt]=(edge){x,y,head[x]};
        head[x]=cnt;
    }
    
    void init(){
        cnt=top=cur=0;
        memset(cut,false,sizeof(cut));
        memset(con,false,sizeof(con));
        memset(head,0,sizeof(head));
        memset(dfn,0,sizeof(dfn));
        memset(low,0,sizeof(low));
        for(int i=1;i<=n;i++)
         dis[i][0]=dis[i][1]=inf;
    }
    
    void tarjan(int x,int fa){
        int num=0;if(x==n) con[x]=true;
        low[x]=dfn[x]=++cur;
        for(int i=head[x];i;i=e[i].next){
            int y=e[i].y;
            if(!dfn[y]){
                tarjan(y,x);
                low[x]=min(low[x],low[y]);
                con[x]|=con[y];
                if(dfn[x]<=low[y]&&con[y])//判断con[y]:当因为dfn[x]<=low[y]知道是割点的时候会y的子树分开,如果最后判断x会造成分开的子树不含n 
                  cut[x]=true;
            }
            else if(y!=fa)  low[x]=min(low[x],dfn[y]);
        }
    }
    
    void solve(){
        read(n);read(m);
        init();
        for(int i=1;i<=m;i++){
            int x,y;
            read(x);read(y);
            if(x==y) continue;
            add(x,y);add(y,x);
        }
        tarjan(1,0);
        for(int i=2;i<n;i++)
         if(cut[i])
          sta[++top]=i;
        printf("%d
    ",top);
        for(int i=1;i<=top;i++)
         printf("%d ",sta[i]);
        putchar(10);
    }
    
    int main(){
        freopen("home.in","r",stdin);
        freopen("home.out","w",stdout);
        read(t);
        while(t--)solve();
    }
    /*
    2 
    4 3
    1 2
    2 3
    3 4
    5 5
    1 2
    2 3
    3 4
    4 5
    4 1
    */
    home

  • 相关阅读:
    不吐不快之EJB演练——开篇概述
    URL重写:RewriteCond指令与RewriteRule 指令格式
    刚到公司有点压力山大,在此希望有大神给点正能量
    053第449题
    选择排序---简单选择排序 堆排序
    bzoj-1492 货币兑换Cash (2)——CDQ分治
    MySQL 提高Insert性能
    Codeforces Round #313 (Div. 2) 560C Gerald&#39;s Hexagon(脑洞)
    Matlab矩阵基础
    Android 带清除功能的输入框控件EditTextWithDel
  • 原文地址:https://www.cnblogs.com/sto324/p/11620730.html
Copyright © 2020-2023  润新知