题目链接:
http://codeforces.com/problemset/problem/376/C
题目大意:
给一个很大的数,这个数一定包含1,6,8,9这4个数字,当然可能还有其他数字。现在要重新排列这些数字获得一个新的数字,要求不出现前导零并且被7整除。
思路:
能被7整除的数,一定是有规律可循的。
先明确:10的零次幂除以7余1; 10的一次幂除以7余3; 10的二次幂除以7余2; 10的三次幂除以7余6; 10的四次幂除以7余4; 10的五次幂除以7余5; 10的六次幂除以7余1(循环了)、、、对于任意一个数,用其相应位数乘以位数幂的余数,这几个数相加以后,看和能不能被7整除,如果能被整除那么这个数也一定能被整除。
比如343=3*2+4*3+3*1->21能被7整除。
那么再看这道题,因为一定有1,6,8,9这4个数字,而这4个数字的组合方式有24种。不同的组合我们可以发现他们除以7取余数的范围是0-6,也就是说,我们可以通过构造一个新的能被7整除的数来解决这个问题。
所以对于一个大数,我们可以先除去0,然后选出1,6,8,9这4种数字(每种只选一个),剩下的那些数字我们可以相加取模,那么就可以得到除以7以后的余数x。然后我们再把含有1,6,8,9的四位数放到后面,就是形成了[num][1689]的形式。那么num所处的位置是10的四次幂,所以我们可以计算出4*x,只要取[1689]中的某一个组合获得余数y,使得4*x+y能被7整除即可。
代码:
#include<stdio.h>
#include<string.h>
char s[1000005],ans[1000005];
char ap[10][5]={"1869","1968","1689","6198","1698","1986","1896"}; //分别代表余数从0-6的组合
int main()
{
int i,j,k,l,num,f1,f2,f3,f4,t,sum;
while(scanf("%s",&s)!=EOF)
{
t=0;
sum=0;
f1=f2=f3=f4=1;
memset(ans,0,sizeof(ans));
num=0;
l=strlen(s);
for(i=0;i<l;i++)
if(s[i]=='0')num++;
for(i=0;i<l;i++)
{
if(s[i]=='0')continue;
if(s[i]=='1'&&f1)
{f1--;continue;}
if(s[i]=='6'&&f2){
f2--;
continue;
}
if(s[i]=='8'&&f3){
f3--;
continue;
}
if(s[i]=='9'&&f4){
f4--;
continue;
}
ans[t++]=s[i];
sum=(sum*10+s[i]-'0')%7;
}
printf("%s",ans);
if(sum==0)printf("%s",ap[0]);
if(sum==1)printf("%s",ap[3]); //1*10000+y
if(sum==2)printf("%s",ap[6]);
if(sum==3)printf("%s",ap[2]);
if(sum==4)printf("%s",ap[5]);
if(sum==5)printf("%s",ap[1]);
if(sum==6)printf("%s",ap[4]);
for(i=0;i<num;i++) //尾部添加0
printf("0");
printf("\n");
}
return 0;
}