【擴充套件KMP】【HDU 4333】Revolving Digits
阿新 • • 發佈:2018-11-19
題意:
給定一個字串,然後將字串最後的字母不斷移動到字串的首字母位置,需要求出在這個移動的過程中,生成的字串比原串字典序大、相等、小的所有字串個數。移動過程中,相同的字串不重複計算。
思路:
由於是比較字典序,因此需要進行字首比較。自然地想到要使用擴充套件kmp知識,我們這裡先大概回憶一下擴充套件kmp知識。
next [ i ] : 模板串從 i 開始擷取的子串與原串的最大字首匹配長度
ex [ i ] : 匹配串從 i 開始擷取的子串與模板串的最大字首匹配長度
可以用線性時間求出這兩個陣列。
我們再來看這個題,就變成了一個水題。就是將這個串*2拼在一起,然後對於這個新串求一遍next陣列即可。現在問題在於如何處理 “相同的字串不重複計算” 這個問題,很自然地可以想到迴圈節。
令 cnt = 串S迴圈節在串S中出現了幾次。
則對於這個串可能出現的所有串中,每個串出現的重複次數為cnt。因此最後的答案需要除以cnt。
總結:
擴充套件KMP就是用來計算字首匹配長度的,應用於各類字首匹配問題。
程式碼:
#include <cstdio> #include <iostream> #include <cstring> #include <algorithm> #define rep(i,a,b) for(int i = a; i <= b; i++) using namespace std; typedef long long ll; const int INF = 2147483640; const double eps = 1e-8; const int N = 3*100000+100; //字串長度最大值 char a[N]; int nxt[N]; //ex陣列即為extend陣列 //預處理計算next陣列 int get(char* tp) { int nxtt[N]; char s[N]; memset(nxtt,0,sizeof nxtt); int l = strlen(tp); for(int i = l+1; i >= 1; i--) s[i] = tp[i-1]; int j = 0; for(int i = 2;i <= l;i ++) { while(j && s[j+1] != s[i]) j = nxtt[j]; if(s[j+1] == s[i]) j ++; nxtt[i] = j; } return l-nxtt[l]; } void GETNEXT(char *str) { int i=0,j,po,len=strlen(str); nxt[0]=len;//初始化next[0] while(str[i]==str[i+1]&&i+1<len)//計算next[1] i++; nxt[1]=i; po=1;//初始化po的位置 for(i=2;i<len;i++) { if(nxt[i-po]+i<nxt[po]+po)//第一種情況,可以直接得到next[i]的值 nxt[i]=nxt[i-po]; else//第二種情況,要繼續匹配才能得到next[i]的值 { j=nxt[po]+po-i; if(j<0)j=0;//如果i>po+next[po],則要從頭開始匹配 while(i+j<len&&str[j]==str[j+i])//計算next[i] j++; nxt[i]=j; po=i;//更新po的位置 } } } int main(int argc, char const *argv[]) { int T; scanf("%d",&T); rep(kk,1,T) { scanf("%s",a); int len = strlen(a); int tp = get(a); int ans = len/tp; // if(len % tp == 0) ans = len/tp; rep(i,len,2*len-1) a[i] = a[i-len]; a[2*len] = '\0'; GETNEXT(a); int c1 = 0,c2 = 0,c3 = 0; rep(i,0,len-1) { if(a[i] == '0'){ c1++; continue; } int tp = nxt[i]; if(tp >= len) c2++; else{ if(a[tp]-'0' < a[i+tp]-'0') c3++; else c1++; } } printf("Case %d: ",kk); printf("%d %d %d\n",c1/ans,c2/ans,c3/ans); } return 0; } /* 字串從0開始編號 next[i]: 模板串從i開始擷取的子串與原串的最大字首匹配長度 ex[i]: 匹配串從i開始擷取的子串與模板串的最大字首匹配長度 */