Revolving Digits
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
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4333
题意:
给你一个T,有T组数据,每组数据给你一个n,问你把n后面的数移到前面形成的数比原来n大还是小还是相等。输出小于n,等于n,大于n的个数。例如:n = 123,首先可以把23移到1前面形成231比原来大,还可以把3移到前面形成312比原来大,还可以不移动还是123和原来相等。(形成的数中不可以存在重复,例如1111,只能产生一个1111).
思路:
KMP中的next[]数组指的是模式串中最长公共前后缀。x[i-next[i]…i-1] = x[0…next[i]-1]。例如123123,next[6] = 3。例如12121212,next[8]=6.
如果不理解KMP算法可以看一下(强烈推荐)https://www.bilibili.com/video/av11866460
扩展KMP中的next数组表示模式串中x[i…m-1]与x[0…m-1]最长公共前缀(与KMP中的next数组不是一回事)。
扩展KMP中的extend[]数组表示T与S[i,n-1]的最长公共前缀。举个例子: 主串S,模式串T,extend[0] = 4, extend[1] = 3, extend[2] = 2,extend[3]=1, extend[4] = 0, extend[5] = 2。
说了这么多,跟这个题有毛关系呢。。。
这个题利用的是extend数组,首先把串复制到后面一次,例如123,即123123。这样是为了求每一位的后缀与自身的最长公共前缀。还是举个例子。
例如341,这时让主串为复制后的341341,模式串为341。
extend[1] 就是让413和341进行匹配,此时extend[1]=0,如果这时不是全匹配,那么就肯定不是相等的,只需判定s[i+extend[i]]与t[extend[i]]谁大谁小即可。
extend[2] = 0,判断s[2]与t[0]谁大谁小。
这时extend[3]=3,此时extend[3] = m,那么他是全匹配的,所以是相等的。
就是利用extend数组这样的特性来求出的。不过还要注意有循环节的情况。例如12121212和1111。
12121212
21212121
12121212
21212121
剩下的全部都是重复的了,还需要用KMP中的next数组来求出他的循环节。例如12121212,next[n]=6。如果n%(n-next[n])==0,说明这时候里面是有循环节,是有重复的。重复的次数为n/(n-next[n])次,所以最后个数除以n/(n-next[n])就可以。。。。。
代码:
#include<bits/stdc++.h>
using namespace std;
void kmp_pre(string s, int m, int NEXT[])
{
int i, j;
j = NEXT[0] = -1;
i = 0;
while(i < m) {
while(-1 != j && s[i] != s[j])
j = NEXT[j];
NEXT[++i] = ++j;
}
}
void pre_EKMP(string t, int m, int Next[])
{
Next[0] = m;
int j = 0;
while( j + 1 < m && t[j] == t[j+1]) j++;
Next[1] = j;
int k = 1;
for(int i = 2; i < m; i++) {
int p = Next[k] + k-1;
int L = Next[i-k];
if(i + L < p+1) Next[i] = L;
else {
j = max(0, p-i+1);
while(i+j<m && t[i+j] == t[j]) j++;
Next[i] = j;
k = i;
}
}
}
void EKMP(string t, int m, string s, int n, int Next[], int extend[])
{
pre_EKMP(t, m ,Next);
int j = 0;
while(j < n && j < m && t[j] == s[j]) j++;
extend[0] = j;
int k = 0;
for(int i = 1; i < n; i++)
{
int p = extend[k] + k-1;
int L = Next[i-k];
if(i+L < p+1) extend[i] = L;
else {
j = max(0, p-i+1);
while(i+j<n && j < m && s[i+j] == t[j]) j++;
extend[i] = j;
k = i;
}
}
}
int main()
{
int p;
cin >> p;
int Case = 0;
while(p--) {
string s, t;
cin >> t;
s = t;
s += t;
int m = t.length();
int n = s.length();
int extend[100005];
int Next[100005];
int NEXT[100005];
memset(extend, 0, sizeof(extend));
memset(Next, 0, sizeof(Next));
memset(NEXT, 0, sizeof(NEXT));
kmp_pre(s, m, NEXT);
EKMP( t, m, s, n, Next, extend);
int L, E, G;
L= E =G=0;
for(int i = 0; i < n-m; i++) {
if(extend[i] == m) {
E++;
}
else {
if(s[i+extend[i]] > t[extend[i]])
G++;
else
L++;
}
}
if(!(m%(m-NEXT[m]))) {
int k = m / (m-NEXT[m]);
printf("Case %d: %d %d %d\n", ++Case,L/k, E/k, G/k);
}
else {
printf("Case %d: %d %d %d\n", ++Case,L, E, G);
}
}
return 0;
}