• hdu 6086 Rikka with String


      OvO <- http://acm.hdu.edu.cn/showproblem.php?pid=6086

      ( 2017 Multi-University Training Contest - Team 5 - 1002 )

      首先,如果没要求左右对称的话

      对所有给定串,建一个AC自动机,

      开一个dp数组,dp[i][j][k]代表长度为i的时候,状态在AC自动机上第j个节点,匹配到的串的状态为k(将匹配到哪些给定串的状态压缩),所得到的串的数量

      然后遍历长度i=(0~m-1),对于每个i遍历AC自动机上的节点j=(0~ac.T-1),对于每个j用k遍历ac自动机的字符集(‘0’和‘1’)

      nxt=next[j][k],表示节点j对于字符k的转移后的节点,flag为节点j所能取到的状态(对其fail数组递归)

      然后对于dp[i][j][k]向后转移。

      那么状态转移为 dp[i+1][nxt][k|flag]=dp[i+1][nxt][k|flag]+dp[i][j][k]。

      那么加左右对称的条件的话,我们对于每个给定串,对于每个字符前的空位,判断是否根据这个空位翻转,

      具体翻转:

        以11001为例,下文'|'表示对称轴的位置

        1. 首先是对于第一个空,也就是第一个1前面的空(|11001),可以对其整体作翻转,

        11001翻转后变为10011,然后取反,也就是01100,也就是说,在长度为1~L的串中匹配到了01100的话,那后半部分必然有一个11001,

        所以可以把01100插入到AC自动机里。

        2. 对于第二个空,(1|1001),  

        

         很明显有下划线的1和0匹配不上,所以舍弃这次翻转。

        3. 对于第三个空位(11|001)

        

        这是合法的,结果串为011,可见如果在计算长度为L的串的dp值时候,如果匹配到了011串,那么整个2L串中是有11001这个串的,

        那么就可以把这个串插入AC自动机中,另外做一个标记,表示这个匹配只在计算长度为L的串时才有效。

        4. 对于剩下几个空位的翻转与上面类似

      这样dp数组就需要开得很大,所以把dp[i][j][k]的第1维改成滚动数组。计算dp数组的时候只要计算长度为L的串的数量即可。

      

      (赛时少写了一个与操作和一个等于号,卡了2小时,淦 O∧O)

      

    #include <stdio.h>
    #include <string.h>
    #include <iostream>
    #include <algorithm>
    #include <queue>
    
    using namespace std;
    
    struct Trie
    {
        static const int MAX_SIZE=500044;
        static const int CHRSET_SIZE=54;
        static const int HASH_SIZE=144441;
        int chrset_size;
        int hash[HASH_SIZE];
        int next[MAX_SIZE][CHRSET_SIZE],fail[MAX_SIZE],end[MAX_SIZE],end2[MAX_SIZE];
        int root,L;
        int gethash(char key[])
        {
            int len = strlen(key);
            for(int i=0;i<len;i++)
                hash[key[i]]=i;
        }
        int newnode()
        {
            for(int i = 0;i < chrset_size;i++)
                next[L][i] = -1;
            end2[L] = 0;
            end[L++] = 0;
            return L-1;
        }
        void init(char key[])
        {
            chrset_size=strlen(key);
            gethash(key);
            L = 0;
            root = newnode();
        }
        void insert(char s[],int num,int flag)
        {
            int len = strlen(s);
            int now = root;
            for(int i = 0;i < len;i++)
            {
                if(next[now][hash[s[i]]] == -1)
                    next[now][hash[s[i]]] = newnode();
                now=next[now][hash[s[i]]];
            }
            if(flag==1)
                end[now]|=(1<<num);
            else
                end2[now]|=(1<<num);
        }
        void build()
        {
            queue<int>Q;
            fail[root] = root;
            for(int i = 0;i < chrset_size;i++)
                if(next[root][i] == -1)
                    next[root][i] = root;
                else
                {
                    fail[next[root][i]] = root;
                    Q.push(next[root][i]);
                }
            while(!Q.empty())
            {
                int now = Q.front();
                Q.pop();
                for(int i = 0;i < chrset_size;i++)
                    if(next[now][i] == -1)
                        next[now][i] = next[fail[now]][i];
                    else
                    {
                        fail[next[now][i]] = next[fail[now]][i];
                        Q.push(next[now][i]);
                    }
            }
        }
        int query(char buf[])
        {
            int len = strlen(buf);
            int now = root;
            int ret = 0;
            for(int i = 0;i < len;i++)
            {
                now = next[now][hash[buf[i]]];
                int temp = now;
                while(temp != root)
                {
                    ret += end[temp];
                    end[temp] = 0;
                    temp = fail[temp];
                }
            }
            return ret;
        }
    } ac;
    
    const int mod=998244353;
    
    int n;
    char key[44];
    char str[144];
    char str2[144];
    int dp[2][8044][70];
    int ans;
    
    void solve(int m)
    {
        int i,j,t,nxt,tmp,flag,wh,k;
        memset(dp,0,sizeof(dp));
        dp[0][0][0]=1;
        t=m;
        for(t=0;t<m;t++)
        {
            wh=t&1;
            memset(dp[1-wh],0,sizeof(dp[1-wh]));
            for(i=0;i<ac.L;i++)
                for(j=0;j<ac.chrset_size;j++)
                {
                    tmp=nxt=ac.next[i][j];
                    flag=0;
                    flag|=ac.end[nxt];
                    if(t+1==m)
                        flag|=ac.end2[nxt];
                    while(ac.fail[tmp]!=0)
                    {
                        tmp=ac.fail[tmp];
                        flag|=ac.end[tmp];
                        if(t+1==m)
                            flag|=ac.end2[tmp];
                    }
    //                cout<<t<<' '<<i<<' '<<j<<' '<<nxt<<' '<<flag<<' '<<1-wh<<' '<<n<<endl;
                    for(k=0;k<=(1<<n)-1;k++)
                        dp[1-wh][nxt][k|flag]=(0ll+dp[1-wh][nxt][k|flag]+dp[wh][i][k])%mod;
                }
    //        printf("
    ");
    //        for(i=0;i<ac.L;i++)
    //        {
    //            for(k=0;k<=(1<<n)-1;k++)
    //                printf("%d",dp[wh][i][k]);
    //            printf(" ");
    //        }
    //        printf("
    ");
    //        for(i=0;i<ac.L;i++)
    //        {
    //            for(k=0;k<=(1<<n)-1;k++)
    //                printf("%d",dp[1-wh][i][k]);
    //            printf(" ");
    //        }
    //        printf("
    
    ");
        }
        ans=0;
        for(i=0;i<ac.L;i++)
            ans=(0ll+ans+dp[m&1][i][(1<<n)-1])%mod;
        printf("%d
    ",ans);
    }
    
    int main()
    {
        bool flagstr;
        int cas,i,j,t;
        int L,len,len2;
        scanf("%d",&cas);
        while(cas--)
        {
            scanf("%d%d",&n,&L);
            for(i=0;i<2;i++)
                key[i]='0'+i;
            key[2]='';
            ac.init(key);
            for(i = 0;i < n;i++)
            {
                scanf("%s",str);
                ac.insert(str,i,1);
                len=strlen(str);
                for(j=0;j<len;j++)    
                {
                       flagstr=true;
                    if(j>len-j)
                    {
                        for(t=0;t<j;t++)
                            str2[t]=str[t];
                        str2[j]='';
                        for(t=0;t<len-j;t++)
                            if(str[j+t]==str2[j-(t+1)])
                            {
                                flagstr=false;
                                break;
                            }
                    }
                    else
                    {
                        for(t=len-1;t>=j;t--)
                            str2[len-(t+1)]='0'+1-(str[t]-'0');
                        str2[len-j]='';
                        for(t=0;t<j;t++)
                            if(str[t]==str[j+(j-t)-1])
                            {
                                flagstr=false;
                                break;
                            }
                    }
    //                cout<<j<<' '<<str2<<' '<<flagstr<<endl;
                    if(j==0)
                    {
                        ac.insert(str2,i,1);
                        continue;
                    }
                    if(flagstr)
                        ac.insert(str2,i,2);
                }
            }
            ac.build();
            solve(L);
        }
        return 0;
    }
    /*
    
    10
    2 2
    0
    1
    2 2
    011
    001
    2 3
    011
    001
    
    */
    

      

     

      

      

  • 相关阅读:
    基于Dubbo的压测调优实例
    R语言之Apriori算法应用
    Linux中的用户和组
    R语言中的循环及其扩展:iter和foreach
    R在Windows下连接Oracle数据库
    R语言之机器学习程序包(更新)
    R语言之数据结构
    windows环境下node安装教程(超详细)
    windows环境下elasticsearch安装教程(超详细)
    MongoDB分片介绍
  • 原文地址:https://www.cnblogs.com/FxxL/p/7308355.html
Copyright © 2020-2023  润新知