2015-2016 下半學期 第二週 訓練(2)

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 1e8

using 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 1e8

using 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 1e8

using 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 1e8

using 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 1e8

using namespace std;

#define lz 2*u,l,mid
#define rz 2*u+1,mid+1,r
const 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

題意:求矩形周長並

{待補)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章