2015-2016 下半学期 第二周 训练(2)

来源:互联网 发布:手立视高清网络摄像机 编辑:程序博客网 时间:2024/05/19 19:15

1、hdu3336

题意:相同前缀的次数和。

题解:利用了KMP中next数组的含义,从j直接跳到next[j]的原因是next[j]~j中不会再有和1~j中的相同前缀。

     next[i]表示了模式串p[1~i-1]中最大的相同的前缀和后缀的长度。

PS:关于KMP的具体讲解 请看这篇文章,http://blog.csdn.net/v_july_v/article/details/7041827

代码:

#include<cstdio>#include<cstring>#include<cmath>#include<algorithm>#include<iostream>#include<queue>#include<vector>#include<set>#include<stack>#include<map>#include<ctime>#include<bitset>#define LL long  long#define db double#define EPS 1e-15#define inf 1e8using namespace std;char s[2000000];int nxt[2000000];int MOD=10007;void get(){    int i=0,j=-1;    nxt[0]=-1;    while (s[i]!='\0'){        if (j==-1 || s[j]==s[i]){            i++,j++;            nxt[i]=j;        }        else j=nxt[j];    }}int main(){    int T,len,ans;    scanf("%d",&T);    while (T--){        memset(nxt,0,sizeof(nxt));        scanf("%d %s",&len,s);        get();        ans=len;        for (int i=1;i<=len;i++){            int tmp=nxt[i];            while (tmp){                ans=(ans+1)%MOD;                tmp=nxt[tmp];            }        }        printf("%d\n",ans);    }    return 0;}

2、hdu4763

题意:在所给字符串中寻找E···E···E形式的最长E。

题解:根据next数组的意义next[len]满足的串形式首尾相同,即在剩下的串种寻找相同的子串,可以适当缩小子串长度。

代码:

#include<cstdio>#include<cstring>#include<cmath>#include<algorithm>#include<iostream>#include<queue>#include<vector>#include<set>#include<stack>#include<map>#include<ctime>#include<bitset>#define LL long  long#define db double#define EPS 1e-15#define inf 1e8using namespace std;const int MAXN = 1000100;char str[MAXN];char tmp[MAXN];int nextval[MAXN];int len;void get(char *s,int lenth){    int i=0,j=-1;    nextval[0]=-1;    while (i<lenth){        if (j==-1 || s[i]==s[j]){            i++; j++;            if(s[i]!=s[j]) nextval[i]=j;            else nextval[i]=nextval[j];        }        else j=nextval[j];    }    return ;}bool KMP(char *t,char *s,int lenth,int lenn){    int i=0,j=0;    while (j<lenn){        if (i==-1 || s[j]==t[i]){            i++; j++;            if (i==lenth) return 1;        }        else i=nextval[i];    }    return 0;}int main(){    int T;    scanf("%d",&T);    while (T--){        scanf("%s",str);        len=strlen(str);        get(str,len);        int ans=nextval[len];        while (ans>len/3) ans=nextval[ans];        while (ans>0){            if (KMP(str,&str[ans],ans,len-ans-ans))                break;            ans=nextval[ans];        }        if (ans<0) printf("%d\n",len/3);        else printf("%d\n",ans);    }    return 0;}

3、hdu2594

题意:给出字符串A,B,求A的前缀和B的后缀相同的最大长度。

题解:两个字符串中间添加一个不会出现的特殊符号,然后对合并后的串求一下next。

代码:

#include<cstdio>#include<cstring>#include<cmath>#include<algorithm>#include<iostream>#include<queue>#include<vector>#include<set>#include<stack>#include<map>#include<ctime>#include<bitset>#define LL long  long#define db double#define EPS 1e-15#define inf 1e8using namespace std;void get(char *x,int m,int nxt[]){    int i=0,j=-1;    nxt[0]=-1;    while (i<m){        if (j==-1 || x[i]==x[j]){            i++,j++;            if (x[i]!=x[j]) nxt[i]=j;            else nxt[i]=nxt[j];        }        else j=nxt[j];    }    return ;}int nxt[100010];int main(){    char str1[100010];    char str2[50010];    while (~(scanf("%s%s", str1, str2))){        int tmp1=strlen(str1);        str1[tmp1]='&';        str1[tmp1+1]='\0';        strcat(str1,str2);        int tmp=strlen(str1);        memset(nxt,0,sizeof(nxt));        get(str1,tmp,nxt);        if (nxt[tmp]){            for (int i=0;i<nxt[tmp];i++){                printf("%c",str1[i]);            }            printf(" ");            printf("%d\n",nxt[tmp]);        }        else printf("%d\n",nxt[tmp]);    }    return 0;}

4、hdu3746

题意:字符串中任意字符必须以“段“的形式重覆两次,问最少需要添加几个字符。

题解:next数组的意义就是代表模式串中必须是成段对称,所以求个next然后根据重复的段长度求个%。

代码:

#include<cstdio>#include<cstring>#include<cmath>#include<algorithm>#include<iostream>#include<queue>#include<vector>#include<set>#include<stack>#include<map>#include<ctime>#include<bitset>#define LL long  long#define db double#define EPS 1e-15#define inf 1e8using namespace std;const int N = 100002;char str[N];int nxt[N];void get(int len){    int i;    int j=0;    for(nxt[1]=0,i=2;i<=len;i++)    {        while(j && str[j+1]!=str[i]){            j=nxt[j];        }        if(str[j+1]==str[i]){            j++;        }        nxt[i]=j;    }}int main(){    int t;    scanf("%d",&t);    while(t--)    {        scanf("%s", str + 1);        int len = strlen(str + 1);        get(len);        int x =len-nxt[len];        if(len%x==0 && len!=x){            printf("0\n");        }        else{            printf("%d\n",x-nxt[len]%x);        }    }    return 0;}

5、poj1151

ACdreamer有一种非线段树的写法,不过分析了复杂度发现是递归的n^3复杂度。 在这里补上线段树的nlogn写法。

题意:求矩形面积并。

题解:扫描线+线段树。将矩形的竖边删掉,剩下的横匾按照y值排序,由小到大,每个矩形下端的边称之为入边,标记为+1,上端的边称之为出边,标记为-1。每个node节点维护当前这个区间内的被覆盖的长度,被标记的大小,即(+1-1+1-1)这种形式的和,以确定扫到了哪里。从下往上扫的时候,遇到+1则更新被覆盖长度,遇到-1则相乘并累加。

代码:

#include<cstdio>#include<cstring>#include<cmath>#include<algorithm>#include<iostream>#include<queue>#include<vector>#include<set>#include<stack>#include<map>#include<ctime>#include<bitset>#define LL long  long#define db double#define EPS 1e-15#define inf 1e8using namespace std;#define lz 2*u,l,mid#define rz 2*u+1,mid+1,rconst int maxn=4222;db sum[maxn];db flag[maxn];db X[maxn];struct Node{    db lx, rx, y;    int s;    Node(){};    Node(db lx_,db rx_,db y_,db s_){        lx=lx_, rx=rx_, y=y_, s=s_;    }    bool operator <(const Node &S) const{        return y<S.y;    }}line[maxn];int find(db tmp,int n){    int l=1,r=n,mid;    while (l<=r){        mid=(l+r)>>1;        if (X[mid]==tmp) return mid;        else if(X[mid]<tmp) l=mid+1;        else r=mid-1;    }}void pushup(int u ,int l,int r){    if (flag[u]) sum[u]=X[r+1]-X[l];    else if (l==r) sum[u]=0;    else sum[u]=sum[2*u]+sum[2*u+1];}void update(int u,int l,int r,int tl,int tr,int c){    if (tl<=l && r<=tr){        flag[u]+=c;        pushup(u,l,r);        return ;    }    int mid=(l+r)>>1;    if (tr<=mid) update(lz,tl,tr,c);    else if (tl>mid) update(rz,tl,tr,c);    else {        update(lz,tl,mid,c);        update(rz,mid+1,tr,c);    }    pushup(u,l,r);}int main(){    int n,cas=0;    while (~scanf("%d",&n),n){        int num=0;        memset(flag,0,sizeof(flag));        memset(sum,0,sizeof(sum));        for (int i=1;i<=n;i++){            db x1,x2,y1,y2;            scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);            line[num++]=Node(x1,x2,y1,1);            X[num]=x1;            line[num++]=Node(x1,x2,y2,-1);            X[num]=x2;        }        sort(X+1,X+1+num);        sort(line+1,line+1+num);        int k=1;        for (int i=2;i<=num;i++)            if (X[i]!=X[i+1]) X[++k]=X[i];        db ans=0;        for (int i=1;i<num;i++){            int l=find(line[i].lx,k);            int r=find(line[i].rx,k)-1;            update(1,1,k,l,r,line[i].s);            ans+=sum[1]*(line[i+1].y-line[i].y);        }        printf("Test case #%d\n",++cas);        printf("Total explored area: %.2f\n\n",ans);    }    return 0;}

6、poj1177

题意:求矩形周长并

{待补)

0 0
原创粉丝点击