Codeforces Round #542 [Alex Lopashev Thanks-Round] (Div. 1) C(二分+KMP)

时间:2022-12-19 16:27:44

http://codeforces.com/contest/1129/problem/C

#include<bits/stdc++.h>
#define fi first
#define se second
#define INF 0x3f3f3f3f
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define pqueue priority_queue
#define NEW(a,b) memset(a,b,sizeof(a))
#define lowbit(x) (x&(-x))
#define si(x) scanf("%d",&x)
#define sl(x) scanf("%lld",&x)
#define lc (d<<1)
#define rc (d<<1|1)
const double pi=4.0*atan(1.0);
const double e=exp(1.0);
const int maxn=1e6+8;
typedef long long LL;
typedef unsigned long long ULL;
const LL mod=1e9+7;
const ULL base=1e7+7;
using namespace std;
LL a[maxn],b[maxn],Next[maxn];
LL dp[3008][3008];
void get_next(int m){
    Next[0]=-1;
    int k=-1;
    int j=0;
    while(j<m){
        while(k>-1&&b[k]!=b[j]){
            k=Next[k];
        }
        if(b[k]==b[j]||k==-1){
            k++;
        }
        Next[++j]=k;
    }
}
bool kmp(int n,int m){
    int k=0;
    for(int i=n-m+1;i<=n;i++){
        b[k++]=a[i];
    }
    get_next(m);
    k=0;
    for(int i=0;i<n;i++)
    {
        while(k>0&&b[k]!=a[i]){
            k=Next[k];
        }
        if(b[k]==a[i]){
            k++;
        }
        if(k==m){
            return 1;
        }
    }
    return 0;
}
bool check(int l){
    if(a[l]==0&&a[l+1]==0&&a[l+2]==1&&a[l+3]==1) return 0;
    if(a[l]==0&&a[l+1]==1&&a[l+2]==0&&a[l+3]==1) return 0;
    if(a[l]==1&&a[l+1]==1&&a[l+2]==1&&a[l+3]==0) return 0;
    if(a[l]==1&&a[l+1]==1&&a[l+2]==1&&a[l+3]==1) return 0;
    return 1;
}
int main(){
    int n;
    LL sum=1;
    scanf("%d",&n);
    for(int i=0;i<n;i++){
        scanf("%d",&a[i]);
        if(i==0){
            dp[0][0]=1;
            printf("1\n");
        }
        else{
            int l=1,r=i;
            int ans=0;
            while(l<=r){
                int mid=(l+r)>>1;
                if(kmp(i,mid)){
                    l=mid+1;
                    ans=max(ans,mid);
                }
                else{
                    r=mid-1;
                }
            }
            dp[i][i]=1;
            if(i>0) dp[i-1][i]=1;
            if(i>1) dp[i-2][i]=1;
            if(i>2&&check(i-3)) dp[i-3][i]=1;
            for(int j=i-4;j>=0;j--){
                dp[j][i]+=dp[j][i-4]*dp[i-3][i];
                dp[j][i]%=mod;
            }
            for(int j=i-3;j>=0;j--){
                dp[j][i]+=dp[j][i-3]*dp[i-2][i];
                dp[j][i]%=mod;
            }
            for(int j=i-2;j>=0;j--){
                dp[j][i]+=dp[j][i-2]*dp[i-1][i];
                dp[j][i]%=mod;
            }
            for(int j=i-1;j>=0;j--){
                dp[j][i]+=dp[j][i-1]*dp[i][i];
                dp[j][i]%=mod;
            }
            for(int j=i-ans;j>=0;j--){
              sum+=dp[j][i];
              sum%=mod;
            }
            printf("%lld\n",sum);
        }
    }
}