Revolving Digits
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.
1
341
Sample Output
Case 1: 1 1 1
题意:给一个数,可以将后n位数放到前面,问能产生多少数大于,小于和等于原来的数,相等的数算一个;
思路:数的位数比较大,用字符串存储,可以将后i(i>=1&&i<=n)位数提到前面,所以总共组成n个数,还需要判重,对应于等于原来的数的数肯定有equ=1,如果一个字符串旋转后有相同的串,那么原串中有最小循环节(置换群, 旋转循环节的最不懂了),可以用KMP->next公式求出循环节长度,每一个循环节中产生的数是相同的,那么只求一个循环节中产生的数与原数的大小就行了,一个循环节产生中的数一定不相同,那么第二个问题就是如何快速高效比较字符串的大小了,枚举串,一个个比较肯定不行,注意到旋转后的串与原串进行比较,就相当于将两个原串合并成一个串然后求某一位的后缀与原串的LCP,就是扩展KMP的用处了(后缀数组还没学会,先不管了),处理处模式串的next值就行了,我这里求了len<<1长度的next,其实求len长度的就行了,然后在一个循环节内枚举每一位通过next[i],来快速判断与原串的大小就行了;
失误:不会的东西太多了,几天了,终于写出来一个题了,后缀数组还是放弃吧,自己太菜,还理解不了,先把能学的学了; 这一个题联系到EXKMP,KMP求字符串最小循环节,值得好好理解; 还有就是用next编译过不了,还是改成nextval;
AC代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN=1e5+33;
char str[MAXN<<1];
int nextval[MAXN<<1];
void Getnextval(char *T,int *nextval,int L)
{
nextval[0]=-1;
int i=0,j=-1;
while(i<L)//需求出next[L]:预判
{
if(j<0||T[i]==T[j]) nextval[++i]=++j;
else j=nextval[j];
}
}
void Exnextval(char *T,int *nextval,int LT)
{
nextval[0]=LT;
int i=0;
while(i+1<LT&&T[i]==T[i+1]) ++i;
nextval[1]=i; int id=1;
for(i=2;i<LT;++i)
{
int mx=id+nextval[id]-1,L=nextval[i-id];
if(i+L-1>=mx)
{
int j=max(mx-i+1,0);
while(j+i<LT&&T[i+j]==T[j]) ++j;
nextval[i]=j;
id=i;
}
else nextval[i]=L;
}
}
int main()
{
int T,i,Kase=0;
scanf("%d",&T);
while(T--)
{
scanf("%s",str);
int l=strlen(str);
Getnextval(str,nextval,l);
int s;
if(l%(l-nextval[l])==0&&nextval[l]) s=l-nextval[l];
else s=l;
for(i=0;i<l;++i) str[i+l]=str[i];
str[l+l]='\0';
Exnextval(str,nextval,l<<1);
int les=0,gre=0;
for(i=0;i<s;++i)
{
if(nextval[i]<l)
{
if(str[nextval[i]+i]>str[nextval[i]]) ++gre;
else les++;
}
}
printf("Case %d: %d %d %d\n",++Kase,les,1,gre);
}
return 0;
}