1. 程式人生 > >【逐位確定法】

【逐位確定法】

之前 ces 整數 cst 預處理 clu 小寫 題意 根據

題目: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; }

【逐位確定法】