bzoj 3768: spoj 4660 Binary palindrome二进制回文串

Description

给定k个长度不超过L的01串,求有多少长度为n的01串S满足:

1.该串是回文串

2.该串不存在两个不重叠的子串,在给定的k个串中。

即不存在a<=b<c<=d,S[a,b]是k个串中的一个,S[c,d]是k个串中的一个

(It does not contain two non-overlapped substrings in the given list of K binary strings.)

举个例子,若给定2(k=2)个01串:101和1001

1010001和1010101均不满足条件。前者不满足条件1,后者不满足条件2

Input

第一行两个整数n,k

以下k行,每行一个01串

Output

输出一个整数表示答案,答案mod 1000000007(10^9+7)

对原串和反串分别建ac自动机,从两边向中间处理回文串,同时在自动机上走,若匹配到一个串就记录并回到起点

dp状态表示为 当前已确定前缀、后缀在ac自动机上的位置,以及是否已匹配到一个串 的方案数

最后检查是否在跨过中点的位置匹配到一个串

#include<cstdio>
#include<cstring>
#include<algorithm>
const int P=1e9+7;
int n,k,ls[33];
char s[33][33];
inline void inc(int&a,int b){
    b+=a-P;
    a=b+(b>>31&P);
}
struct acam{
    int ch[907][2],fa[907];
    int S[907][33];
    bool e[907];
    int ptr;
    acam(){
        memset(this,0,sizeof(acam));
        ptr=1;
        ch[0][0]=ch[0][1]=1;
    }
    void ins(char*s,int a){
        int w=1;
        for(int i=0;s[i];++i){
            int c=s[i]-‘0‘,&u=ch[w][c];
            if(!u)u=++ptr;
            w=u;
            S[w][a]|=1<<i;
        }
        e[w]=1;
    }
    void ins(char*s,int a,int len){
        int w=1;
        for(int i=len-1;i>=0;--i){
            int c=s[i]-‘0‘,&u=ch[w][c];
            if(!u)u=++ptr;
            w=u;
            S[w][a]|=1<<i;
        }
        e[w]=1;
    }
    void build(){
        int q[907],ql=0,qr=0;
        q[++qr]=1;
        while(ql!=qr){
            int w=q[++ql];
            for(int i=0;i<2;++i){
                int&u=ch[w][i];
                (u?fa[q[++qr]=u]:u)=ch[fa[w]][i];
            }
        }
        for(int i=2;i<=qr;++i){
            int w=q[i],f=fa[w];
            e[w]|=e[f];
            for(int j=0;j<k;++j)S[w][j]|=S[f][j];
        }
    }
}t1,t2;
int f[2][907][907][2];
int main(){
    scanf("%d%d",&n,&k);
    for(int i=0;i<k;++i){
        scanf("%s",s[i]);
        ls[i]=strlen(s[i]);
        t1.ins(s[i],i);
        t2.ins(s[i],i,ls[i]);
    }
    t1.build();
    t2.build();
    int now=0;
    f[0][1][1][0]=1;
    for(int t=0;t<n/2;++t,now^=1){
        memset(f[now^1],0,sizeof(f[0][0])*(t1.ptr+2));
        for(int c=0;c<2;++c){
            for(int a=1;a<=t1.ptr;++a)if(!t1.e[a]){
                int a1=t1.ch[a][c],is=0;
                if(t1.e[a1])a1=1,is=1;
                int(*f1a)[2]=f[now^1][a1];
                int(*f0a)[2]=f[now][a];
                for(int b=1;b<=t2.ptr;++b)if(!t2.e[b]){
                    int b1=t2.ch[b][c];
                    int v=is;
                    if(t2.e[b1])b1=1,++v;
                    for(int x=0;x+v<2;++x){
                        inc(f1a[b1][x+v],f0a[b][x]);
                    }
                }
            }
        }
    }
    if(n&1){
        memset(f[now^1],0,sizeof(f[0][0])*(t1.ptr+2));
        for(int c=0;c<2;++c){
            for(int a=1;a<=t1.ptr;++a)if(!t1.e[a]){
                int a1=t1.ch[a][c],is=0;
                if(t1.e[a1])a1=1,is=1;
                int(*f1a)[2]=f[now^1][a1];
                int(*f0a)[2]=f[now][a];
                for(int b=1;b<=t2.ptr;++b)if(!t2.e[b]){
                    int v=is;
                    for(int x=0;x+v<2;++x){
                        inc(f1a[b][x+v],f0a[b][x]);
                    }
                }
            }
        }
        now^=1;
    }
    int ans=0;
    for(int a=1;a<=t1.ptr;++a){
        for(int b=1;b<=t2.ptr;++b){
            inc(ans,f[now][a][b][0]);
            for(int c=0;c<k;++c)if(t1.S[a][c]<<1&t2.S[b][c])goto o;
            inc(ans,f[now][a][b][1]);
            o:;
        }
    }
    printf("%d\n",ans);
    return 0;
}
时间: 2024-10-18 02:02:16

bzoj 3768: spoj 4660 Binary palindrome二进制回文串的相关文章

Palindrome Number(回文串)

题目: Determine whether an integer is a palindrome. Do this without extra space. 分析: 该题目来源于leetcode.回文串是一个正读和反读都一样的字符串,比如"level"或者"noon"等等就是回文串.当然整数形式的回文串也是类似的.但负数不是回文串.两种思路: 按定义来,依次比较串的首尾,直到中间相隔1个或0个元素(取决于整数是奇数位数还是偶数位数).优点是当不是回文串时,可以很快发

UVa 10617 Again Palindrome(回文串区间DP)

UVa 10617 Again Palindrome(经典回文串区间DP) 题意: 给定一个字符串s,对s进行删除操作,使得剩下的子串是回文字符串,问最多有多少种这种子串. 思路: 涉及到回文字符串,首先要想到的肯定是区间DP,如何写出状态转移方程? 直接从题意切入:dp[i, j]表示区间[i, j]最多有多少个这样的子串. 1. s[i] == s[j] 去掉s[i],则一个子问题就是dp[i+1, j]; 去掉s[j],另一个子问题就是dp[i, j-1]; 显然这两个子问题是会有重叠的,

HDU 1513 Palindrome 求回文串

这个题是走弯路了,刚开始自己DP出了方程,无限MLE,唉 if(s1[i]==s1[j]) dp[i][j]=dp[i+1][j-1]; else dp[i][j]=min(dp[i][j-1],dp[i+1][j]) +1; 后来百度了一下,这个原来是个经典回文串问题,即先将串置反,然后求LCS........ 然后就是这题卡时间卡的特别厉害,多用了一次strlen就TLE AC: #include<cstdio> #include<string> #include<str

Uva 10617 Again Palindrome (DP+回文串)

Problem I Again Palindromes Input: Standard Input Output: Standard Output Time Limit: 2 Seconds A palindorme is a sequence of one or more characters that reads the same from the left as it does from the right. For example, Z, TOT and MADAM are palind

[虚拟机OA]Break a Palindrome 破坏回文串

In this challenge, you will be given a palindrome which you must modify if possible. Change exactly one character of the string to another character in the range ascii[a-z] so that the string meets the following two conditions: • The new string is no

POJ--3974 Palindrome(回文串,hash)

链接:点击这里 #include<iostream> #include<algorithm> #include<stdio.h> #include<cstring> using namespace std; #define maxn 1000005 #define LL long long #define ull unsigned long long const LL P = 131; ull p[maxn+10],f[maxn],ff[maxn]; int

Valid Palindrome ——判断字符串是否为回文串

本文是在学习中的总结,欢迎转载但请注明出处:http://blog.csdn.net/pistolove/article/details/41488377 Valid Palindrome Given a string, determine if it is a palindrome, considering only alphanumeric characters and ignoring cases. For example, "A man, a plan, a canal: Panama&

URAL 1297. Palindrome(后缀数组求最大回文串)

题目大意:给你一串字符串,让你求出来它存在的最长连续的回文串. 解题思路:先把字符串逆序加到数组中,然后用后缀数组求解.两种方法:1,枚举排名,直接比较rank相同的字符串的位置差是不是len.如果是的话,就记录求解:2,枚举地址,求第i地址与第2*len-i+1的lcp的最大值. PS:需要注意如果多解输出靠前的字符串. 两种写法写在了一起,分别是Del,和Del1函数. 1297. Palindrome Time limit: 1.0 second Memory limit: 64 MB T

2565: 最长双回文串 - BZOJ

Description 顺序和逆序读起来完全一样的串叫做回文串.比如acbca是回文串,而abc不是(abc的顺序为"abc",逆序为"cba",不相同). 输入长度为n的串S,求S的最长双回文子串T,即可将T分为两部分X,Y,(|X|,|Y|≥1)且X和Y都是回文串.Input 一行由小写英文字母组成的字符串S. Output 一行一个整数,表示最长双回文子串的长度.Sample Input baacaabbacabb Sample Output 12 HINT