Ural1095

1095. Nikifor 3

Time limit: 1.0 second
Memory limit: 64 MB
Nikifor knows that a certain positive integer has in its decimal form each of the digits 1,2,3,4. You are asked to determine if Nikifor can rearrange the digits of the number in such a way that the new number divides by 7.

Input

The first line contains the number  N (not exceeding 10000) of positive integers that are to be checked. The next  N lines contain these integers. Each number has no more than 20 digits.

Output

For each of the  N numbers output a number divisible by 7 that can be obtained from the corresponding number from the input data by a rearrangement of the digits. If such rearrangement does not exist you should output 0 in the corresponding line. In the case of several valid rearrangements you may find only one of them.

Sample

input output
2
1234
531234
4123
354123
Problem Author: Dmitry Filimonenkov
题意:给你N个正整数,它们都含有数码1、2、3、4,不超过20位,要求你调整每个正整数中数字的顺序,使它能被7整除。


最朴素的做法,暴搜它的每一种排列,但20位就挂了,肯定TLE。


注意题目中有条件每个正整数都有1,2,3,4,所以应该好好利用这个条件才对。


那么我们可以把1,2,3,4各取出一个,会发现它们组成的四位数模7的余数有7种。


我取了这样一组数4123,1324,4321,2341,1432,2413,4213,它们模7分别余0,1,2,3,4,5,6


剩下的数码随便排列就可以了(0放最后),用这7个数填补其它数码组成的数字模7剩余的部分即可。
以上参考别人的思路。
思路已经很清晰了。。。
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include<cstring>
#include <algorithm>
#include <math.h>
using namespace std;
int res[]={4123,1324,4321,2341,1432,2413,4213};
int c[10];
int main()
{
	char ch[25];
	int cas;
	int i,j,len;
	scanf("%d",&cas);
	while(cas--)
	{
		memset(c,0,sizeof(c));
		scanf("%s",ch);
		len=strlen(ch); 
		for(i=0;i<len;i++)
		{
			c[ch[i]-'0']++;
		}
		c[1]--;c[2]--;c[3]--;c[4]--;
		int cnt=0;
		long long  num=0;
		for(i=1;i<10;i++)
		{
			if(c[i])
			{
				for(j=0;j<c[i];j++)
				{
					cout<<i;
				    cnt++;
				    num*=(long long)10;
				    num+=(long long)i;
				   // num%=7;
				}
				  
			}
		}
		int tmp=num%7; // ????????????????
		tmp*=10000;
		tmp%=7;
		if(tmp==0)
		cout<<res[0];
		else 
		cout<<res[7-tmp];
		if(cnt+4<len)
		{
			for(i=cnt+4+1;i<=len;i++)cout<<"0";
		}
		cout<<endl;
		
	//	cout<<num<<endl;
	}
}

刚开始自己写的老师WA2,然后就看自己和别人的代码的区别,发现自己sum取余的时候弄错了,因为sum是除去1234之后剩下的,所以要乘上10000,然后再取余才能是结果。( 刚开始还想不明白。。。真是醉了,还是神牛告诉我的当然要乘以10000辣。。。。。。)就是(sum*10000+1234(的组合))%7==0 那么,sum*10000的取余7的结果加上1234组合取余7的结果为0,同时sum*10000%7==( ( sum%7)*10000)%7 因为sum*10000会超出long long 的取值范围。这是一个数学公式
如果a%b=c,那么(a*k)%b=a%b+a%b+…+a%b=c+c+…+c=kc(k>0)
另外别人的做法是,每次sum+=(sum*10+i)%7 然后计算 (sum*10000)%7 结果是一样的。
另外关于取余,想到了中国剩余定理,所以就写一下吧,博客里也没有写到过。
中国剩余定理 ,首先要从一个古老的数学题开始
  在《孙子算经》中有这样一个问题:“今有物不知其数,三三数之剩二(除以3余2),五五数之剩三(除以5余3),七七数之剩二(除以7余2),问物几何?”这个问题称为“孙子问题”
 那么我们首先假设满足除3余2的数为n1,满足除5余3的是n2,满足除7余2的是n3 
那么由a%b==c那么(a+kb)%b==c这个公式,我们知道若想(n1+n2+n3)%3==2就要n2,n3 是3的倍数,同理(n1+n2+n3)%5==3 n1,n3是5的倍数,(n1+n2+n3)%7==2,n1,n2是7的倍数,所以,
  1. n1除以3余2,且是5和7的公倍数。
  2. n2除以5余3,且是3和7的公倍数。
  3. n3除以7余2,且是3和5的公倍数。所以他的本质就是   从5和7的公倍数中找除3余2的+从3和7的公倍数中找除5余3的+从3和5的公倍数中找除7余2 。。那么找数字的时候也可以用到上面得公式 找除3余2的就可以找除3余1的然后乘以2,最后可能这个结果不是最小的,然后可以处以3和5和7的最小公倍数,答案就是最小的。

大概就是这些了,另外附上一些大神门关于除7取余的经典解法

Matrix67大神的博客

一位有趣的大神的博客
http://hi.baidu.com/curioz/item/27812e32fdb8bb149dc65eda 这个里面还有很多好玩的链接,(*^__^*) 嘻嘻……



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值