USACO Section 3.1 Contact - AC自动机..


     赤果果的AC自动机~并且比较阉割~比完整的AC自动机好写多了..

 首先构造一个完全二叉树..根据题目要求构造13层..根节点为1,根的左孩子为2,右孩子为3..依次类推..那么一个节点P的父亲为P/2...左孩子为P*2...右孩子为P*2+1..所以整棵树用一维数组来存就okl了...这棵树转化为字典数..可以看成..1是超级节点..2是'0'...3是'1'..4是'00'..5是'01'..6是'10'..7是'11'..依次类推...

 构造Fail指针很方便~~初值: father[1]=0 , father[2]=father[3]=1 然后一个for循环就可以了...

 AC自动机做好后就边读边做匹配了~~计数器不仅是当前指针的位置++...其所有的father再father等等的也都++...当所到达的层数大于13时那么指针就不下去就是~~

    输出有点恶心...我WA了6次有5次是输出的问题~这个~~~根据题目和数据自己调调吧~~

Program:

/*  
ID: zzyzzy12  
LANG: C++  
TASK: contact
*/    
#include<iostream>    
#include<istream>
#include<stdio.h>    
#include<string.h>    
#include<math.h>    
#include<stack>
#include<algorithm>    
#include<queue> 
#define oo 2000000000
#define ll long long
using namespace std;   
struct node
{
     int w,t;      
}s[20001];
int i,k,p,A,B,N,num,m,father[20001];
char c;
bool cmp(node a,node b)
{ 
     if (a.t!=b.t) return a.t>b.t;
     return a.w<b.w;
}
int main()
{
     freopen("contact.in","r",stdin);  
     freopen("contact.out","w",stdout);   
     for (i=1;i<=20000;i++) 
     {
            s[i].w=i;
            s[i].t=0;    
     }
     father[1]=0; father[2]=father[3]=1;
     for (i=4;i<=20000;i++)
     {
            if (i%2) father[i]=father[i/2]*2+1;
            else father[i]=father[i/2]*2;   
     }
     scanf("%d%d%d\n",&A,&B,&N);
     p=1;
     //2047
     while (~scanf("%c",&c))
     {
            if (c!='1' && c!='0') continue;
            if (c-'0')
            {
                   k=p=p*2+1; 
                   while (k)
                   {
                        s[k].t++; 
                        k=father[k];     
                   }                  
            }else
            {
                   k=p=p*2; 
                   while (k)
                   {
                        s[k].t++; 
                        k=father[k];     
                   }                     
            }
            if (p>4095) p=father[p];
     }
     sort(s+1,s+20000,cmp);
     k=1;
     for (i=1;i<=A;i++) k*=2;
     A=k;
     k=1;
     for (i=1;i<=B+1;i++) k*=2;
     B=k-1;     
     num=0; m=0;
     int out[20],h,g=1;
     for (i=1;i<=20000;i++)
     if (s[i].w>=A && s[i].w<=B)
     {
            if (!s[i].t) break;       
            if (s[i].t!=m)
            {
                   if (num==N) break;
                   if (m && g%6!=0) printf("\n");
                   m=s[i].t; 
                   num++;  g=0;
                   printf("%d\n",m);     
            }
            g++; 
            if (g%6!=1) printf(" "); 
            h=0;
            while (s[i].w!=1)
            {
                  out[++h]=s[i].w%2;
                  s[i].w/=2;      
            }    
            for (i=h;i>=1;i--) printf("%d",out[i]);   
            if (g%6==0) printf("\n");        
     } 
     if (g%6) printf("\n");
     return 0;   
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值