HDU 4333 Revolving Digits 扩展KMP

Revolving Digits Time Limit:1000MS    Memory Limit:32768KB    64bit IO Format:%I64d & %I64u

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
 
题意:给出一个数字,每一次将数字的最后一位拿到第一位得到一个新的数字,问有多少不相同的数字满足:大于原数,等于原数,小于原数的条件。

方法:扩展KMP

思路:这个数很明显要当作字符串来处理。我们在比较两个数字的时候,首先比较第一位,相同则比较下一位,以此类推,直到不同或者全部相同,然而这个比较过程会很漫长,如果有什么办法可以直接得到两个数的最长公共前缀,那就方便多了,直接比较下一位就好了,这里,就需要使用扩展KMP算法。


扩展KMP:两个串,s和T,计算s的所有后缀与T的最长公共字串的长度。


    将数的末端数字拿到首端也可以等价为将原串num复制一遍接到尾部,得到extnum,然后问题就很清楚了,只要让s=extnum,T=num,那么就可以求出所有的数字与原数字的最长公共前缀长度,然后再比较一下就可以了。

    另外,还需要解决重复的问题,这个需要用到循环节的概念,如果一个串经过上述操作会产生相同的数字,那就意味着这个串中含有整数个循环节,否则在拼接的时候肯定不会产生相同的数,比如121拼接完是121121,没有循环部分,而1212拼接完是12121212,很明显12这个开始循环了,因此如果原串中含有整数个循环节,那么只需要把求出来的值除以循环节的个数即可,因为每个循环节所产生的数字一定是一样的。

#include <iostream>
#include <string.h>
#include <stdio.h>
#define MAX 400010
using namespace std;
int g,e,l;
int Next[MAX*2];
char num[MAX],extnum[MAX*2];
void getNext(char *s,int *next)
{
    int nn = strlen(s);
    next[0] = nn;
    int p = 0;
    while (p+1 < nn && s[p] == s[p+1])
        p++;
    next[1] = p;
    int k = 1, L;
    for (int i = 2; i < nn; i++)
    {
        p =     k + next[k] - 1;
        L = next[i - k];
        if (i + L <= p) next[i] = L;
        else
        {
            int j = p - i + 1;
            if (j < 0) j = 0;
            while (i + j < nn && s[i + j] == s[j])
                j++;
            next[i] = j;
            k = i;
        }
    }
    /*    for (int i=0;i<nn;i++){
            cout<< next[i] <<" ";
        }cout<<endl;
    */
}

void getExtend(char *s,char *T,int *extend,int *next)
{
    int nn = strlen(s) ;
    getNext(s,next);
    int p = 0;
    while (p < nn && s[p] == T[p])
        p++;
    extend[0] = p;
    //extend[1] = p;
    int k = 0, L;
    for (int i = 1; i < nn; i++)
    {
        p =     k + extend[k] - 1;
        L = next[i - k];
        if (i + L <= p) extend[i] = L;
        else
        {
            int j = p - i + 1;
            if (j < 0) j = 0;
            while (i + j < nn && s[i + j] == T[j])
                j++;
            extend[i] = j;
            k = i;
        }
    }
}

void getres()
{
    int extlen=strlen(extnum);
    int len=extlen/2;
    for(int i=0;i<len;i++)
	{
		if(Next[i]>=len)
			e++;
		else
		{
			if(extnum[i+Next[i]]<num[Next[i]])
				l++;
			else
				g++;
		}
	}
}

int getFail(char *p)
{
	int f[MAX];
    int m=strlen(p);
    f[0]=f[1]=0;
    for(int i=1; i<m; ++i)
    {
        int j=f[i];
        while(j && p[i]!=p[j])j=f[j];
        f[i+1] = p[i]==p[j]?1+j:0;
    }
    int len=strlen(p);
    return len-f[len];
}

void output(int cas,int len,int loop)
{
	int tol=1;
	if(len%loop==0)
		tol=len/loop;
	l/=tol;
	g/=tol;
	e/=tol;
	printf("Case %d: %d %d %d\n",cas,l,e,g);
}


void show(int len)
{
	for(int i=0;i<len;i++)
	{
		printf("%d ",num[i]);
	}
	printf("\n");
}

void init()
{
    int len=strlen(num);
    //getNext(num,next);
    strcpy(extnum,num);
    for(int i=0; i<len; i++)
        extnum[i+len]=num[i];
	extnum[len*2]='\0';
	getNext(extnum,Next);
    //getExtend(extnum,extnum,ext,next);
}

int main()
{
    int t,cas,loop,len;
    scanf("%d",&t);
    cas=0;
    while(t--)
    {
        g=e=l=0;
        scanf("%s",num);
        len=strlen(num);
        loop=getFail(num);
        init();
        //show(next,strlen(extnum));
        getres();
        //printf("loop=%d\n",loop);
        output(++cas,len,loop);
    }
    return 0;
}








  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
智慧校园整体解决方案是响应国家教育信息化政策,结合教育改革和技术创新的产物。该方案以物联网、大数据、人工智能和移动互联技术为基础,旨在打造一个安全、高效、互动且环保的教育环境。方案强调从数字化校园向智慧校园的转变,通过自动数据采集、智能分析和按需服务,实现校园业务的智能化管理。 方案的总体设计原则包括应用至上、分层设计和互联互通,确保系统能够满足不同用户角色的需求,并实现数据和资源的整合与共享。框架设计涵盖了校园安全、管理、教学、环境等多个方面,构建了一个全面的校园应用生态系统。这包括智慧安全系统、校园身份识别、智能排课及选课系统、智慧学习系统、精品录播教室方案等,以支持个性化学习和教学评估。 建设内容突出了智慧安全和智慧管理的重要性。智慧安全管理通过分布式录播系统和紧急预案一键启动功能,增强校园安全预警和事件响应能力。智慧管理系统则利用物联网技术,实现人员和设备的智能管理,提高校园运营效率。 智慧教学部分,方案提供了智慧学习系统和精品录播教室方案,支持专业级学习硬件和智能化网络管理,促进个性化学习和教学资源的高效利用。同时,教学质量评估中心和资源应用平台的建设,旨在提升教学评估的科学性和教育资源的共享性。 智慧环境建设则侧重于基于物联网的设备管理,通过智慧教室管理系统实现教室环境的智能控制和能效管理,打造绿色、节能的校园环境。电子班牌和校园信息发布系统的建设,将作为智慧校园的核心和入口,提供教务、一卡通、图书馆等系统的集成信息。 总体而言,智慧校园整体解决方案通过集成先进技术,不仅提升了校园的信息化水平,而且优化了教学和管理流程,为学生、教师和家长提供了更加便捷、个性化的教育体验。
经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值