HDU 4333 Revolving Digits(kmp+扩展kmp)
2016-05-03 11:13
447 查看
Description
给定一个数字,每一次将该数的第一位放到放到最后一位,求所有组成的不同的数比原数小的个数,相等的个数,大的个数
Input
第一行一整数T(T<=50)表示用例组数,每组用例占一行为一整数n(n<=10^100000)
Output
输出所有组成的不同的数中比原数小的个数,相等的个数,大的个数
Sample Input
1
341
Sample Output
Case 1: 1 1 1
Solution
因为只考虑不相同的数字,所以至多有len个不同的数(len为n的位数),将n看作一个字符串a,将a扩展两倍,那么这len个不同的数即为a的len个长度为len的子串,这len个数与原数的比较就变成了a的一个后缀的前缀与a的前缀的匹配,如果匹配长度大于等于len则两数相等,如果匹配长度小于len,则比较第一个失配的数字即可判断两数的大小关系,但这样做没有考虑着len个数的重复问题,例如111答案应该是0 1 0但这样做的答案是0 3 0,所以还需要去重,去重很简单,因为只有原串完全由最小循环节组成时才会重复,而且重复次数为len/l,l为最小循环节长度,而求最小循环节长度可以用kmp来解决,l=len-next[len]即为可能的最小循环节长度,判断len%l是否为0即可知道原串是否完全由最小循环节组成,那么重复次数t=len%l==0?len/l:1,最后将三个结果除以t即为去重后的正确答案
Code
给定一个数字,每一次将该数的第一位放到放到最后一位,求所有组成的不同的数比原数小的个数,相等的个数,大的个数
Input
第一行一整数T(T<=50)表示用例组数,每组用例占一行为一整数n(n<=10^100000)
Output
输出所有组成的不同的数中比原数小的个数,相等的个数,大的个数
Sample Input
1
341
Sample Output
Case 1: 1 1 1
Solution
因为只考虑不相同的数字,所以至多有len个不同的数(len为n的位数),将n看作一个字符串a,将a扩展两倍,那么这len个不同的数即为a的len个长度为len的子串,这len个数与原数的比较就变成了a的一个后缀的前缀与a的前缀的匹配,如果匹配长度大于等于len则两数相等,如果匹配长度小于len,则比较第一个失配的数字即可判断两数的大小关系,但这样做没有考虑着len个数的重复问题,例如111答案应该是0 1 0但这样做的答案是0 3 0,所以还需要去重,去重很简单,因为只有原串完全由最小循环节组成时才会重复,而且重复次数为len/l,l为最小循环节长度,而求最小循环节长度可以用kmp来解决,l=len-next[len]即为可能的最小循环节长度,判断len%l是否为0即可知道原串是否完全由最小循环节组成,那么重复次数t=len%l==0?len/l:1,最后将三个结果除以t即为去重后的正确答案
Code
#include<cstdio> #include<iostream> #include<cstring> #include<algorithm> using namespace std; #define maxn 222222 char a[maxn]; int nex[maxn]; void kmp(char *a) { memset(nex,0,sizeof(nex)); int la=strlen(a); for(int i=0,j=-1;i<=la;i++,j++) { nex[i]=j; while(~j&&a[i]!=a[j]) j=nex[j]; } } void extend_kmp(char *a) { int i,j,k,la=strlen(a); nex[0]=la; for(i=0;i+1<la&&a[i+1]==a[i];i++); nex[1]=i; k=1; for(i=2;i<la;i++) { int len=k+nex[k]; nex[i]=min(nex[i-k],max(0,len-i)); while(i+nex[i]<la&&a[nex[i]]==a[i+nex[i]])nex[i]++; if(i+nex[i]>k+nex[k])k=i; } } int main() { int T,res=1; scanf("%d",&T); while(T--) { scanf("%s",a); int len=strlen(a); kmp(a); int t=len%(len-nex[len])==0?len/(len-nex[len]):1; for(int i=len;i<2*len;i++)a[i]=a[i-len]; a[2*len]='\0'; extend_kmp(a); int cnt1=0,cnt2=0,cnt3=0; for(int i=0;i<len;i++) { if(nex[i]>=len)cnt2++; else if(a[nex[i]]>a[i+nex[i]])cnt1++; else cnt3++; } printf("Case %d: %d %d %d\n",res++,cnt1/t,cnt2/t,cnt3/t); } return 0; }
相关文章推荐
- ios 滑动返回 pop
- caffe的LRN层粗解
- iOS应用崩溃日志分析
- 网站集成QQ登录功能
- UIBezierPath精讲
- PS 色彩的色相谱
- 【转】人生应该接受的教育
- Spring入门之初学注解03(@Controller、@Service、@Repository)
- hdoj2011 (java)多项式求和
- for语句
- LeetCode 24. Swap Nodes in Pairs
- std::for_each
- linux下重命名文件
- Android集成支付宝的坑
- ajax 请求
- CALayer精讲
- Swift— Swift编码规范之命名规范-备
- 布局参数
- listView设置条目分隔线
- Android getWidth和getMeasuredWidth 区别