POJ2541 Binary Witch [状态压缩]

  这题是在做KMP分类里做到的,网上搜到的题解也基本都是KMP解的。但这题根本不是KMP,在网上找了个KMP的程序,随便rand了10组数据,跑了10多秒。

  题意比较纠结,就是说给你一个长度为N的串S,找出S[k..k+t-1]=s[N-t+1..N],其中1<=t<=13,k<=N-t,有多个k满足时,选择t最大的并且最靠右的,令S[N+1]=S[k+t],如果找不到符合条件的的K,则S[N+1]='0'。

  正解应该是压缩状态,每个子串都由01组成,可以看作一个2进制数,因为t的范围<=13,所以用2^13就可以表示出所有的子串,用last[i][j]表示长度为i内容为j的子串的最晚结束位置。只要扫一遍数组就可以了,遇到长度为i内容为j的子串就可以刷新last[i][j]。这样在处理第i位的时候,last中就保存了从1~i-1为所有长度为1~13的子串的最后出现位置。这种解法的复杂度是O((N+M)*13)。

#include <stdio.h>
#include <string.h>

int n,l;
char s[1002000];
int last[13][9000];
int main(){
    while(scanf("%d%d",&n,&l)!=EOF){
        scanf("%s",s);
        memset(last,-1,sizeof last);
        for(int i=0;i<n+l-1;i++){
            int now=0,tmp=1;
            //从i=n开始写入数组的i+1位
            if(i>=n-1)s[i+1]='0';
            for(int j=0;j<13&&i-j>=0;j++){
                int x=s[i-j]-'0';
                if(x)now+=tmp;
                tmp<<=1;
                //从i=n开始写入数组的i+1位
                if(i>=n-1&&last[j][now]!=-1)s[i+1]=s[last[j][now]+1];
                //写入的同时更新last,这样每次在找i的时候存的就是1~i-1的所有长度为1~13的子串最后结束位置
                last[j][now]=i;
            }
        }
        s[n+l]='\0';
        printf("%s\n",s+n);
    }
    return 0;
}
posted @ 2012-08-03 11:31  Burn_E  阅读(433)  评论(0编辑  收藏  举报