AcWing《算法竞赛进阶指南》哈希

138. 兔子与兔子

#include <iostream>
#include<algorithm>
#include<string.h>
using namespace std;
typedef unsigned long long ULL;
const int N = 1000010,base = 131;
ULL HASH[N], POW[N];

char str[N];

ULL getHash(int i, int j) {

	return HASH[j] - HASH[i - 1] * POW[j - i + 1];
}

int main()
{
	scanf("%s", str + 1);
	int len = strlen(str + 1);
	POW[0] = 1;
	for (int i = 1; i <= len; i++) {
		POW[i] = POW[i - 1] * base;
		HASH[i] = HASH[i - 1] * base + str[i] - 'a';
	}
	int T;
	cin>>T;
	for(int cases=1;cases<=T;cases++){
	    
	    int a,b,c,d;
	    cin>>a>>b>>c>>d;
	    if(getHash(a,b)==getHash(c,d))
	        cout<<"Yes"<<endl;
	    else
	        cout<<"No"<<endl;
	}
	return 0;
}

139. 回文子串的最大长度

#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
typedef unsigned long long ULL;
const int N=2000020,base=131;

ULL leftHash[N],rightHash[N];
ULL POW[N];
char str[N];

ULL getHash(int i,int j,ULL HASH[]){
    return HASH[j]-HASH[i-1]*POW[j-i+1];
}

int main()
{
    int T=1;
    while(scanf("%s",str+1),strcmp(str+1,"END"))
    {
        int len=strlen(str+1);
        for(int i=2*len;i>0;i-=2){
            str[i]=str[i/2];
            str[i-1]='#';
        }
        len*=2;
        POW[0]=1;
        for(int i=1,j=len;i<=len;i++,j--)
        {
            POW[i]=POW[i-1]*base;
            leftHash[i]=leftHash[i-1]*base+str[i]-'a'+1;
            rightHash[i]=rightHash[i-1]*base+str[j]-'a'+1;
        }
        int ans=0;
        for(int i=1;i<=len;i++)
        {
            int l=0,r=min(i-1,len-i);
            while(l<r)
            {
                int mid=(l+r+1)>>1;
                //右起前缀数组索引与字符索引的映射关系
                //1~n,2~n-1,...,i+1~n-i,i+mid~n+1-i-mid;   (i+1,i+mid)~(n-i,n+1-i-mid) 
                if(getHash(i-mid,i-1,leftHash)!=getHash(len+1-i-mid,len-i,rightHash))
                    r=mid-1;
                else
                    l=mid;
            }
            if (str[i - l] <= 'z' && str[i-l]>='a') 
                ans = max(ans, l + 1);
            else 
                ans = max(ans, l);
            scanf("%d",ans);
        }
        printf("Case %d: %d\n",T++,ans);
    }
    return 0;
}

140. 后缀数组

#include<iostream>
#include<algorithm>
#include<limits.h>
#include<string.h>

using namespace std;
typedef unsigned long long ULL;
const int N=300010,base=131;
ULL POW[N],HASH[N];
char str[N];
int n;
int suffix[N];

ULL getHash(int i,int j){
    return HASH[j]-HASH[i-1]*POW[j-i+1];
}


int getLongestCommonPrefix(int i,int j){
    
    int l=0,r=min(n-i+1,n-j+1);
    while(l<r){
        int mid=(l+r+1)>>1;
        if(getHash(i,i+mid-1)!=getHash(j,j+mid-1))
            r=mid-1;
        else
            l=mid;
    }
    return l;
}

bool compare(int a,int b){
    int len=getLongestCommonPrefix(a,b);
    int a1=a+len>n?INT_MIN:str[a+len];
    int b1=b+len>n?INT_MIN:str[b+len];
    return a1<b1;
}

int main(){
    scanf("%s",str+1);
    n=strlen(str+1);
    POW[0]=1;
    for(int i=1;i<=n;i++){
        POW[i]=POW[i-1]*base;
        HASH[i]=HASH[i-1]*base+str[i]-'a'+1;
        suffix[i]=i;
    }
    
    sort(suffix+1,suffix+n+1,compare);
    
    for(int i=1;i<=n;i++)
        printf("%d ",suffix[i]-1);
    printf("\n");
    for(int i=1;i<=n;i++){
        if(i==1)
            printf("0 ");
        else
        {
            printf("%d ",getLongestCommonPrefix(suffix[i-1],suffix[i]));
        }
    }
    return 0;
}

137. 雪花雪花雪花

#include<iostream>
#include<algorithm>
#include<cstring>

using namespace std; 
const int N=100010;
int snows[N][6];
int idx[N];
int snow[6],isnow[6];
int n;

bool cmpByArray(int a[],int b[])
{
    for(int i=0;i<6;i++){
        if(a[i]<b[i])
            return true;
        else if(a[i]>b[i])
            return false;
    }
    return false;
}

bool comparator(int a,int b)
{
    return  cmpByArray(snows[a],snows[b]);
}

void getMinString(int* arr)  //求解某个序列的最小字符串表示
{
    static int a[12];
    for (int i = 0; i < 12; i ++ ) 
        a[i] = arr[i % 6];

    int i = 0, j = 1, k;
    while (i < 6 && j < 6)
    {
        for (k = 0; k < n && a[i + k] == a[j + k]; k ++ );
        if (k == 6) break;

        if (a[i + k] > a[j + k])
        {
            i += k + 1;
            if (i == j) i ++ ;
        }
        else
        {
            j += k + 1;
            if (i == j)
                j ++ ;
        }
    }
    k = min(i, j);

    for (i = 0; i < 6; i ++ ) 
        arr[i] = a[i + k];
}

int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        for(int j=0;j<6;j++)
        {
            cin>>snow[j];
            isnow[5-j]=snow[j];
        }
        getMinString(snow);
        getMinString(isnow);
        if(cmpByArray(snow,isnow))
            memcpy(snows[i], snow, sizeof snow);
        else
            memcpy(snows[i], isnow, sizeof isnow);
        idx[i]=i;
    }
    
    sort(idx+1,idx+1+n,comparator);
    bool flag=false;
    for(int i=2;i<=n;i++)
    {
        if(!cmpByArray(  snows[idx[i-1]],snows[idx[i]] ) && !cmpByArray(  snows[idx[i]],snows[idx[i-1]] ))
        {
            flag=true;
            break;
        }
    }
    if(flag)
        cout<<"Twin snowflakes found."<<endl;
    else
        cout<<"No two snowflakes are alike."<<endl;
    return 0;
}

136. 邻值查找

#include <iostream>
#include <limits.h>
#include <set>
#include <algorithm>
using namespace std;

typedef long long LL;
typedef pair<int,int> PII;
set<PII> record;
const int N=100010;
int arr[N];

int main(){
    
    int n;
    scanf("%d",&n);
    cin>>arr[1];
    record.insert({INT_MIN,0});
    record.insert({INT_MAX,0});
    record.insert({arr[1],1});
    int i=2;
    while(i<=n){
        cin>>arr[i];
        auto right=record.lower_bound({arr[i],i});
        LL val=INT_MAX,index=-1;
        if(right!=record.end())
        {
            val=min(val,right->first-(LL)arr[i]);
            index=right->second;
        }
        if(right!=record.begin()){
             right--;
             
             if(arr[i]-(LL)right->first<val){
                 val=arr[i]-(LL)right->first;
                 index=right->second;
                 
             }
             else if(arr[i]-(LL)right->first==val){
                 if(arr[right->second]<arr[index])
                 {
                     index=right->second;
                 }
             }
        }
        cout<<val<<" "<<index<<endl;
        record.insert({arr[i],i});
        i++;
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值