H.String Problem

题意:输入一个字符串,求其最大表示法和最小表示法分别在字符串中出现的次数。
分析:先求出最小,最大表示法,然后将s复制一遍(只复制len-1个字符),分别把最小,最大表示跑一边kmp,输出答案。

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 2e6+5;
char s[maxn],t1[maxn],t2[maxn];
int Next1[maxn],Next2[maxn];
int Getmin(char *s,int len);            //最小表示法求取
int Getmax(char *s,int len);            //最大表示法求取
void GetNext(char *s,int Next[],int len);
int Gettimes(char *s,char *t,int len1,int len2,int Next[]);
int main(){
    while (~scanf ("%s",s+1)){
        int len = strlen(s+1);
        int minx = Getmin(s+1,len),maxx = Getmax(s+1,len);
        for (int i=1;i<len;i++)     s[i+len] = s[i];
        for (int i=1,j1=minx,j2=maxx;i<=len;i++,j1++,j2++){
            t1[i] = s[j1];
            t2[i] = s[j2];
        }
        GetNext(t1,Next1,len);      GetNext(t2,Next2,len);
        printf ("%d %d %d %d\n",minx,Gettimes(s,t1,len*2-1,len,Next1),maxx,Gettimes(s,t2,len*2-1,len,Next2));
    }
    return 0;
}
void GetNext(char *s,int Next[],int len){
    for (int i=2,j=0;i<=len;i++){
        while (j && s[i]!=s[j+1])   j = Next[j];
        if (s[i]==s[j+1])   j++;
        Next[i] = j;
    }
    return;
}
int Gettimes(char *s,char *t,int len1,int len2,int Next[]){
    int ans = 0;
    for (int i=1,j=0;i<=len1;i++){
        while (j && s[i]!=t[j+1])   j = Next[j];
        if (s[i]==t[j+1])   j++;
        if (j==len2){
            ans++;
            j = Next[j];
        }
    }
    return ans;
}
int Getmin(char *s,int len){
    int i=0,j=1,k=0;
    while (i<len && j<len && k<len){
        int t = s[(i+k)%len] - s[(j+k)%len];
        if (!t) k++;
        else{
            if (t>0)    i = i+k+1;
            else    j = j+k+1;
            if (i==j)   j++;
            k = 0;
        }
    }
    return min(i,j)+1;
}
int Getmax(char *s,int len){
    int i=0,j=1,k=0;
    while (i<len && j<len && k<len){
        int t = s[(i+k)%len] - s[(j+k)%len];
        if (!t) k++;
        else{
            if (t<0)    i = i+k+1;
            else    j = j+k+1;
            if (i==j)   j++;
            k = 0;
        }
    }
    return min(i,j)+1;
}

J. Query

题意:给出两个字符串,若干次询问,每次询问要么更改某个字符串的某个字符的值,要么询问两字符串从下标i开始有多少了连续字符相等。
分析:可以用树状数组,1表示两字符串该位置相同,0表示不同,统计区间内1的数量sum(i),当sum(r)-sum(l-1)==r-l+1时,说明l-r区间内的字符都相等,利用二分求答案。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int maxn = 1e6+6;
int c[maxn];
char s1[maxn],s2[maxn],s[20];
inline int lowbit(int i){return i&(-i);}
int sum(int i){       //求前i为的和
    int ans = 0;
    while (i){
        ans += c[i];
        i -= lowbit(i);
    }
    return ans;
}
void update(int i,int k,int len){
    while (i<=len){
        c[i] += k;
        i += lowbit(i);
    }
    return;
}
int search(int l,int r){
    int mid = (l+r)/2;
    while (l!=r){
        mid = (l+r)/2 + ((l+r)&1);
        if (sum(mid)-sum(l-1)==mid-l+1)   l = mid;
        else    r = mid-1;
    }
    return s1[l]==s2[l]?l:l-1;
}
int main(){
    int t,cases=0;
    scanf ("%d",&t);
    while (t--){
        memset(c,0,sizeof c);
        printf ("Case %d:\n",++cases);
        scanf ("%s %s",s1+1,s2+1);
        int len = min(strlen(s1+1),strlen(s2+1)),q,x,y,flag;
        int l,r;
        char ch;
        for (int i=1;i<=len;i++)    if (s1[i]==s2[i])
            update(i,1,len);
        scanf ("%d",&q);
        while (q--){
            scanf ("%d",&flag);
            if (flag==1){
                scanf ("%d %d %c",&x,&y,&ch);   y++;
                if (y>len)  continue;
                int tmp = (s1[y]==s2[y]);
                if (x==1)   s1[y] = ch;
                else    s2[y] = ch;
                if (s1[y]==s2[y] && !tmp)   update(y,1,len);
                else if (s1[y]!=s2[y] && tmp)    update(y,-1,len);
            }else{
                scanf ("%d",&x);    x++;
                if (x>len)  continue;
                printf ("%d\n",search(x,len)-x+1);
            }
        }
    }
    return 0;
}

0 条评论

发表评论

邮箱地址不会被公开。