timus 1547. Password Search【题意思路+大数模板】

题目地址传送门:URAL 1547

这道题需要用到大数的很多模板,推荐大家去刷刷!

题目大意:Vova忘记了在Timus OJ上面的密码了,密码是由小写字母(a~z)组成的,他只知道密码长度不大于n位,现在他需要用m台数据处理器对密码进行检索,其中检索顺序需要满足字典序。比如他的密码长度不大于2,那就需要依次检索a,b,..........,y,z,aa,ab,..........,zy,zz.输出每台数据检索器的检索区间,使得总的检索效率可以达到最高。

已知密码的总可能数不少于数据处理器个数。

对于这个题目,刚开始是有点懵的。以为只用一次的26进制就可以表示所有的数(a到zzzzz..........z),后来发现是不行的

接下来发现还有这种密码还有这样一个特性:

当密码长度为一位(a,b,..........,z):数量为26,即密码长度不大于1总数为26

            长度为二位(aa,ab,..........,zz):数量为26*26,即密码长度不大于2总数为26+26^2

           ..........

           长度为n位的数量为:26^n,即密码长度不大于n总数为26+26^2+..........+26^n

为使每个数据处理器效率达到最大,需要求出每段区间的数,这里需要用到大数除法求出余数和商,从而确定每个数据处理器的区间个数和起止的区间号

将区间号转换为对应密码长度位数的对应字符串(将十进制转换为二十六进制),输出对应的结果。

这道题需要用到很多个大数模板,于是自己就写了一点,预备着用

1.比较字符串的大小(不含0前缀,且字符串里的元素只有‘0’~‘9’构成

/*
  s1大于s2,返回1
  s1小于s2,返回-1
  s1等于s2,返回0
*/
int cmp(char *s1,char *s2)
{
	int len1=strlen(s1),len2=strlen(s2),i;
	if(len1>len2)return 1;
	else if(len1<len2)return -1;
	for(i=0;i<len1;i++)
		if(s1[i]>s2[i])return 1;
		else if(s1[i]<s2[i])return -1;
	return 0;
}

2.大数相乘,这里只呈现整形和字符串相乘的结果

/*
   执行函数后字符串s2的结果为字符串s1和整形x的结果(x>=0)
*/
void multi(char *s2,char *s1,int x)  
{
	int a[330],len1,i,cnt=0;
	memset(a,0,sizeof(a));
	len1=strlen(s1);
	for(i=0;i<len1;i++)a[i]=s1[len1-i-1]-'0';
	for(i=0;i<len1;i++)a[i]*=x;
	for(i=0;i<len1+5;i++)
	{
		a[i+1]+=a[i]/10;
		a[i]%=10;
	}
	for(i=len1+5;i>0;i--) //如果乘出来的结果可能为0,那就不能在for循环里将i置为i>=0
             if(a[i])break;
	strcpy(s2,"");
	for(;i>=0;i--)s2[cnt++]=a[i]+'0';
	s2[cnt]='\0';
}
3.大数求和
/*
   执行函数后字符串s3返回的是字符串表示的大数s1和s2的和
*/
void add(char *s3,char *s2,char *s1) 
{
	int a1[330],a2[330],len1=strlen(s1),len2=strlen(s2),len,i,cnt=0;
	memset(a1,0,sizeof(a1));
	memset(a2,0,sizeof(a2));
	len=(len1>len2?len1:len2);
	for(i=0;i<len1;i++)a1[i]=s1[len1-i-1]-'0';
	for(i=0;i<len2;i++)a2[i]=s2[len2-i-1]-'0';
	for(i=0;i<len+2;i++)a1[i]=a1[i]+a2[i];
	for(i=0;i<len+2;i++)
	{
		a1[i+1]+=a1[i]/10;
		a1[i]%=10;
	}
	for(i=len+2;i>0;i--)  //如果考虑到相加结果可能为0,那就不能在for循环条件中将i置为i>=0,其他条件一般可以保留
		if(a1[i])break;
	strcpy(s3,"");
	for(;i>=0;i--)s3[cnt++]=a1[i]+'0';
	s3[cnt]='\0';
}

4.大数自加

/*
   返回大数s1自加1后的效果
*/
void addpp(char *s1) 
{
	int i,len=strlen(s1),a[330],cnt=0;
	memset(a,0,sizeof(a));
	for(i=0;i<len;i++)
		a[i]=s1[len-1-i]-'0';
	a[0]++;
	for(i=0;i<len;i++)
	{
		a[i+1]+=a[i]/10;
		a[i]=a[i]%10;
	}
	for(i=len+2;i>=0;i--)if(a[i])break;
	for(;i>=0;i--)s1[cnt++]=a[i]+'0';
	s1[cnt]='\0';
}
5.大数减法
/*
     执行函数后s3表示s2减去s1的结果,其中s2大于等于s1
*/
void minus(char *s3,char *s2,char *s1)  
{
	int a1[330],a2[330],i,len1=strlen(s1),len2=strlen(s2),cnt=0;
	memset(a1,0,sizeof(a1));
	memset(a2,0,sizeof(a2));
	for(i=0;i<len1;i++)a1[i]=s1[len1-i-1]-'0';
	for(i=0;i<len2;i++)a2[i]=s2[len2-i-1]-'0';
	for(i=0;i<len2;i++)
	{
		if(a1[i]>a2[i])
		{
			a2[i+1]--;
			a1[i]=a2[i]+10-a1[i];
		}
		else
		{
			a1[i]=a2[i]-a1[i];
		}
	}
	for(i=len2;i>0;i--) //warning
            if(a1[i])break;
	for(;i>=0;i--)s3[cnt++]=a1[i]+'0';
	s3[cnt]='\0';
}
6.大数自减

/*执行函数后s1返回s1自减1后的结果,其中s1大于0
void minuspp(char *s1) 
{
	int i,len=strlen(s1),a[330],cnt=0;
	memset(a,0,sizeof(a));
	for(i=0;i<len;i++)
		a[i]=s1[len-1-i]-'0';
	a[0]--;
	for(i=0;i<len;i++)
	{
		if(a[i]==-1)
		{
			a[i+1]--;
			a[i]=9;
		}
		else break;
	}
	for(i=len+2;i>0;i--) //warning
              if(a[i])break;
	for(;i>=0;i--)s1[cnt++]=a[i]+'0';
	s1[cnt]='\0';
}
7.大数除法(字符串类型除整形)

/*
     这里num表示全局变量,返回的是s1mod(mm)的值,即余数,s2返回的是s1/mm的值
*/
int num;
void divi(char *s2,char *s1,int mm)
{
	char s3[330];
	int len=strlen(s1),i,cnt=0;
	num=0;
	strcpy(s3,"");
	for(i=0;i<len;i++)
	{
		num=num*10+s1[i]-'0';
		s3[cnt++]=num/mm+'0';
		num=num%mm;
	}
	s3[cnt]='\0';
	for(i=0;i<len-1;i++)  //当考虑到s1可能会小于mm时,在for循环中需要将i置为i<len-1
		if(s3[i]!='0')break;
	cnt=0;
	for(;i<len;i++)
		s2[cnt++]=s3[i];
	s2[cnt]='\0';
}
模板就先整理这几个吧,1547这道题都用上了,或许也还有表述不准确的地方,也希望大家多多指出!


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值