zoukankan      html  css  js  c++  java
  • 明豪的疑惑

    时间限制3.5s,空间512MB

    题目描述

    T组数据,每组给出一段字符串,求其中不同的回文串有几个。

    数据范围

    T<=10,len<=1e6.

    题目解析

    正解是回文自动机,答案为自动机中节点数-2,但是并不会。

    考场上写了一个花里胡哨的马拉车加trie。

    跑马拉车时若当前直接匹配到的地方为cj[i],则用并查集加二分查找找出该点所对应的trie节点,之后继续匹配时向trie中加数,答案是trie中非‘#’字符个数。复杂度O(len *loglen*t).

    爆炸了100——20.无法debug.

    发现其他人暴力过了。于是可以在匹配完成后如果该串长度大于cj[zai*2-i],则暴力往trie中加入该回文串(除第一位外不加‘#’),复杂度O(玄学)。答案即为trie中节点个数-1(多一个‘#’)

    莫得办法。

    代码如下:

    #include<bits/stdc++.h>
    using namespace std;
    const int N=2e6+5;
    int t,cnt,dao,n,cj[N],r,zai,ans,now,dui[200],dapan;
    char c[N],s[N];
    struct pigu
    {
        int er[29];
    }tier[N<<1];
    inline int read()
    {
        char c=getchar();
        int x=0,f=1;
        while(!isdigit(c)) {if(c=='-') f=-1;c=getchar();}
        while(isdigit(c)) {x=(x<<3)+(x<<1)+c-'0';c=getchar();}
        return x*f;
    }
    //inline int pan(int &x)
    //{
    //    if(!x) x=++cnt,dapan++;
    //    return x;
    //}
    //inline int findfa(int x)
    //{
    //    if(fa[x]==x) return x;
    //    fa[x]=findfa(fa[x]);
    //    return fa[x];
    //}
    //inline int find(int zn,int hd)
    //{
    //    int l=0,r=ves[zn].size()-1,zd=0;
    //    while(l<=r)
    //    {
    //        int mid=(l+r)>>1;
    //        if(ves[zn][mid]>=hd) r=mid-1,zd=mid;
    //        else l=mid+1;
    //    }
    //    if(zd==0) return ve[vef[zn][zd]][hd-1];
    //    else return ve[vef[zn][zd]][hd-ves[zn][zd-1]-1];
    //}
    //queue <int> que;
    //inline void qingkongtier()
    //{
    //    que.push(0);
    //    while(!que.empty())
    //    {
    //        int now=que.front();
    //        que.pop();
    //        for(int i=0;i<=dui['$'];i++) if(tier[now].er[i])
    //        {
    //            que.push(tier[now].er[i]);
    //            tier[now].er[i]=0;
    //        }
    //    }
    //}
    inline void insert(int now,int you)
    {
        int nu=0;if(c[now]=='#') nu=tier[nu].er[dui['#']];
        for(int i=now;i<=now+you-1;i++)
        {
            if(c[i]=='#') continue;
            if(tier[nu].er[dui[c[i]]]==0)
            {
                tier[nu].er[dui[c[i]]]=++cnt;
                nu=tier[nu].er[dui[c[i]]];
                memset(tier[nu].er,0,sizeof(tier[nu].er));
            }
            else
                nu=tier[nu].er[dui[c[i]]];
        }
    } 
    int main()
    {
        freopen("confusion.in","r",stdin);
        freopen("confusion.out","w",stdout);
        t=read();
        for(int i='a';i<='z';i++) dui[i]=i-'a';dui['#']='z'-'a'+1;dui['$']='z'-'a'+2;
        while(t--)
        {
            scanf("%s",s+1);
            cnt=1;dao++;zai=r=0;ans=0;
            tier[0].er[dui['#']]=1;
            memset(tier[1].er,0,sizeof(tier[1].er));
            memset(cj,0,sizeof(cj));
            n=strlen(s+1);c[0]='$';c[1]='#';
            for(int i=1;i<=n;i++) {c[i*2]=s[i];c[i*2+1]='#';}
            n=n*2+1;c[n+1]='%';
            for(int i=1;i<=n;i++)
            {
                int sum=0;dapan=0;
                if(i<r)
                      cj[i]=min(r-i,cj[zai*2-i]);
                cj[i]=max(cj[i],1);
                while(c[i+cj[i]]==c[i-cj[i]]) cj[i]++;
                if(cj[i]>cj[zai*2-i]||i>=r) 
                insert(i,cj[i]);
                if(i+cj[i]>r) r=i+cj[i],zai=i;
            }
            memset(tier[0].er,0,sizeof(tier[0].er));
            
            cout<<cnt-1<<"
    ";
        }
        fclose(stdin);
        fclose(stdout);
        return 0;
    }
    /*
    3
    aaaa
    mymom
    abba
    2
    ithinkifiamherehewillnotdie
    auutpppfotttoduergggepsekkssu
    */
  • 相关阅读:
    删除MFC单文档默认菜单栏的两种方法
    mfc更改背景色
    (转)VC单选按钮控件(Radio Button)用法
    转:MFC 基于对话的程序界面显示完全后立即执行一个函数
    转:vc6以上如何给MFC对话框添加OnInitDialog函数
    常用网址
    2010年春季学期C语言程序设计答疑安排
    rdlc导出Excel
    SQL Server查询表的结构
    C# WinForm开发系列 WebBrowser
  • 原文地址:https://www.cnblogs.com/betablewaloot/p/12130205.html
Copyright © 2011-2022 走看看