逐位确定法

Posted ---学习ing---

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了逐位确定法相关的知识,希望对你有一定的参考价值。

题目:CodeForces196-D:The Next Good String

 

题意:给定仅由小写字母组成的字符串S和一个正整数m。求一个长度与S相同的仅由小写字母组成的字符串S1,满足:

  • S1>S
  • S1中不含长度大于等于d的回文串。

思路:许昊然的文章里叫“逐位确定法”,以为之前没见到过官方名字,就姑且这样叫了。具体如下。

 

 

一: 预处理得到大于等于字符串S的最小字典序新串S’:

  •   最后面的连续的‘z‘全部改为‘a’。 因为肯定前面有以为要改,所以后面的越小越好。       
  •  把从后向前扫描的第一位非‘z’位++。

二: 根据上面两步得到了大于字符串S的最小字典序新串S’,然后dfs,得到满足条件的最小字典序新串S1。

 

此题具体实现:

            1,题意等效于不存在长度位d和d+1的回文串。

            2,检查回文串的时候用hash判定即可。

 

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
#define ull unsigned long long
const int maxn=1000000;
const int seed=131;
ull g[maxn],hash1[maxn],hash2[maxn];
int N,M; char c[maxn],ans[maxn];
bool palindrome(int L,int R)
{
    if(L<=0) return false;
    if(hash2[R]-hash2[L-1]==(hash1[R]-hash1[L-1]*g[R-L+1])*g[L-1]) return true;
    return false;
}
bool dfs(int pos,int ismax)
{
    if(pos==N+1) {
        puts(ans+1);
        return true;
    }
    for(ans[pos]=ismax?c[pos]:a;ans[pos]<=z;ans[pos]++){
         hash1[pos]=hash1[pos-1]*seed+ans[pos];
         hash2[pos]=hash2[pos-1]+ans[pos]*g[pos-1];
         if(!palindrome(pos-M+1,pos)&&!palindrome(pos-M,pos)&&dfs(pos+1,ismax&&ans[pos]==c[pos]))
            return true;
    }
    return false;
}
int main()
{
    int i;
    scanf("%d%s",&M,c+1);
    N=strlen(c+1);
    for(i=N;i>=1&&c[i]==z;i--) c[i]=a;
    if(i<=0) {
        puts("Impossible"); return 0;
    }
    c[i]++; g[0]=1;
    for(i=1;i<=N;i++) g[i]=g[i-1]*seed;
    if(!dfs(1,1)) puts("Impossible");
    return 0;
}

 

以上是关于逐位确定法的主要内容,如果未能解决你的问题,请参考以下文章

分治法

Android:通过片段进行相机预览。从活动中确定

LQ0166 串逐位和程序填空

片段中的getView()导致抛出异常,不确定原因

c_cpp 这个简单的代码片段显示了如何使用有符号整数在C中完成插值。 for()循环确定要插入的范围

找到多个名为 [spring_web] 的片段。这对于相对排序是不合法的