HDU 4333(擴展KMP)

Problem Description
One day Silence is interested in revolving the digits of a positive integer. In the revolving operation, he can put several last digits to the front of the integer. Of course, he can put all the digits to the front, so he will get the integer itself. For example, he can change 123 into 312, 231 and 123. Now he wanted to know how many different integers he can get that is less than the original integer, how many different integers he can get that is equal to the original integer and how many different integers he can get that is greater than the original integer. We will ensure that the original integer is positive and it has no leading zeros, but if we get an integer with some leading zeros by revolving the digits, we will regard the new integer as it has no leading zeros. For example, if the original integer is 104, we can get 410, 41 and 104.

Input
The first line of the input contains an integer T (1<=T<=50) which means the number of test cases.
For each test cases, there is only one line that is the original integer N. we will ensure that N is an positive integer without leading zeros and N is less than 10^100000.

Output
For each test case, please output a line which is “Case X: L E G”, X means the number of the test case. And L means the number of integers is less than N that we can get by revolving digits. E means the number of integers is equal to N. G means the number of integers is greater than N.

Sample Input

1
341

Sample Output

Case 1: 1 1 1

題目大意:給你一個數字,然後將這個數字的每一位都向前移動一位,此時的第一位放到最後一位,問這樣得到的數字中有多少個數字是小於原數字,多少個數字是等於原數字,多少個數字是大於原數字的。

解題思路:將這個數字複製一串放到原序列後面,那麼問題就轉換爲以第i位開始的長度爲n的字符串與原字符串的長度,這裏我們介紹一個算法:擴展KMP算法,主要解決的問題是,有兩個字符串t,s,它要求的是字符串s的後綴與字符串t的前綴相等的最大長度。

擴展KMP算法使用的主要是manacher算法的思想:
我們用數組extend[i] 表示s[i]…s[n]與t的前綴相等的最大長度。假設當前遍歷到s串的位置i,即我們已經算出extend[0]…extend[i-1],且我們知道s串中與t串的前綴匹配的一個最右邊的子串的起始位置和結束位置爲a,p,即s[a…p) =t[0…p-a)。然後我們在定義一個數組next[i]表示t[i]…t[m-1]與t的最長相同前綴。即t爲自身的extend數組。然後此時我們知道了s[a…p)等於t[0…p-a),那麼如果i是小於p,就表示i包含在和t數組匹配的子串中,如果此時i+next[i]小於p,next[i],表示串t的後綴與前綴相等的最大長度,那麼extend[i]就等於next[i],否則,就繼續匹配即可。

代碼:

#pragma GCC optimize(2)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <string>
#include <vector>
#include <set>
#include <map>
#include <stack>
#include <bitset>
#include <queue>
//#include <random>
#include <time.h>
using namespace std;
#define int long long
#define ull unsigned long long
#define ls root<<1
#define rs root<<1|1
const int inf=1ll*1<<60;
const int maxn=2e6+10;
const int maxm=3e6+10;
char arr[maxn];
int to[maxn],extend[maxn];
void getextend()
{
    int a=0,p=0;
    extend[0]=strlen(arr);
    for(int i=1;arr[i]!='\0';i++){
        if(i>=p || i+extend[i-a]>=p){
            if(i>=p) p=i;
            while(arr[p]!='\0' && arr[p]==arr[p-i]) p++;
            extend[i]=p-i;
            a=i;
        }
        else extend[i]=extend[i-a];
    }
}
void kmp() {
	int t=-1;
	to[0]=-1;
	for(int i=1; arr[i]!='\0'; i++) {
		t=to[i-1];
		while(t!=-1 && arr[t+1]!=arr[i]) {
			t=to[t];
		}
		if(arr[t+1]==arr[i])to[i]=t+1;
		else to[i]=-1;
	}
}
signed main() {
    int t,test=1;
    scanf("%lld",&t);
    while(t--){
        scanf("%s",arr);
        int l=0,e=0,g=0,len=strlen(arr);
        for(int i=0;i<len;i++)arr[i+len]=arr[i];
        arr[len+len]='\0';
        getextend();
        for(int i=0;i<len;i++){
            if(extend[i]>=len)e++;
            else{
                int x=extend[i];
                if(arr[x]>arr[x+i])l++;
                else g++;
            }
        }
        kmp();
        int res=1,tmp=len-to[len-1]-1;
		if(len%tmp==0) {
			res=len/tmp;
		}
        printf("Case %lld: %lld %lld %lld\n",test++,l/res,e/res,g/res);
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章