【BZOJ】1692: [Usaco2007 Dec]队列变换

【算法】字符串hash

【题解】

显然如果字母互不相同,贪心取是正确的。

如果存在字母相同,那么就换成比较后缀和前缀嘛。

但是要注意,不是后缀和前缀相同就能直接跳跃,每次必须只推一位。

取模的哈希比自然溢出慢了好多。

#include<cstdio>
#include<algorithm>
#include<cstring>
#define ll long long
using namespace std;
const int maxn=30010,MOD=123456789,base=291;
ll sum1[maxn],sum2[maxn],p[maxn];
int n;
char c,s[maxn];
int calc1(int L,int R){return (sum1[R]+MOD-sum1[L-1]*p[R-L+1]%MOD)%MOD;}
int calc2(int L,int R){return (sum2[L]+MOD-sum2[R+1]*p[R-L+1]%MOD)%MOD;}
bool big(int L,int R){
    if(s[L]!=s[R])return s[L]>=s[R];
    int l=1,r=R-L+2;
     while(l<r){
         int mid=(l+r)>>1;
         if(calc1(L,L+mid-1)==calc2(R-mid+1,R))l=mid+1;
         else r=mid;
     }
     return s[L+l-1]>=s[R-l+1];
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        c=getchar();
        while(c<'A'||c>'Z')c=getchar();
        s[i]=c;
    }
    p[0]=1;
    for(int i=1;i<=n;i++)p[i]=p[i-1]*base%MOD;
    for(int i=1;i<=n;i++)sum1[i]=(sum1[i-1]*base+s[i]-'A')%MOD;
    for(int i=n;i>=1;i--)sum2[i]=(sum2[i+1]*base+s[i]-'A')%MOD;
    int L=1,R=n;
    for(int i=1,j=1;i<=n;i++,j++){
        if(!big(L,R)){
            putchar(s[L++]);
        }
        else{
            putchar(s[R--]);
        }
        if(j==80)putchar('\n'),j=0;
    }
    return 0;
}
View Code

 

转载于:https://www.cnblogs.com/onioncyc/p/7445338.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值