首页 > 代码库 > 数论 - 整除问题 --- 整数集合中找出3的最大倍数

数论 - 整除问题 --- 整数集合中找出3的最大倍数

 

Mean: 

 题目描述:给一个包含非负整数的数组(长度为n),找出由这些数字组成的最大的3的倍数,没有的话则输出impossible。

analyse:

首先想到的就是直接暴力,这是最蠢的方法,数据一大的话,必会TLE。

直接用蛮力的话,生成所有的组合,为 2^n个,对每个数字再进行比较判断,需要 O(n)的时间,因为n可能会比较大,需要每个位的比较。
总的时间复杂度为O(n * 2^n). 

 

那么到底要怎么做呢?

首先我们来了解几个数学知识:

1)一个数n对m取余的余数为a1,b为n的每一位数字的和,那么有:n%m=b%m=a1。

  例如,如果对于151和它的各位之和7,对于3的余数都为1。

2)一个数是3的倍数,则该数字各位总和为3的倍数。
  例如,让我们考虑8760,它是3的倍数,因为数字总和为8 + 7 + 6 + 0 = 21,这是3的倍数。

  推论:一个数是3的倍数,那么构成他的数字的排列为一个新的数字,这个数字仍然是3的倍数。

 

Time complexity:O(nlongn)

 

Source code:

 暴力代码:

// Memory   Time// 1347K     0MS// by : Snarl_jsb// 2014-09-10-09.28#include<algorithm>#include<cstdio>#include<cstring>#include<cstdlib>#include<iostream>#include<vector>#include<queue>#include<stack>#include<map>#include<string>#include<climits>#include<cmath>#define N 100#define MAXN 100#define LL long longusing namespace std;long long n,summ;long long a[N];bool cmp(LL a,LL b){    return a>b;}LL ans[N];LL idx;LL Max;void work(int* b,int n){	LL sum1=0;	for(int i=0;i<n;i++)    {        sum1+=a[b[i]];    }    if(sum1%3==0&&sum1>Max)    {        Max=sum1;        idx=n;        for(int i=0;i<n;i++)        {            ans[i]=a[b[i]];        }    }}void _gen_comb(int* a,int s,int e,int m,int& cnt,int* temp){	int i;	if (!m)		work(temp,cnt);	else		for (i=s;i<=e-m+1;i++){			temp[cnt++]=a[i];			_gen_comb(a,i+1,e,m-1,cnt,temp);			cnt--;		}}void gen_comb(int n,int m){	int a[MAXN],temp[MAXN],cnt=0,i;	for (i=0;i<n;i++)		a[i]=i+1;	_gen_comb(a,0,n-1,m,cnt,temp);}int main(){//    freopen("C:\\Users\\ASUS\\Desktop\\cin.cpp","r",stdin);//    freopen("C:\\Users\\ASUS\\Desktop\\cout.cpp","w",stdout);    while(~scanf("%I64d",&n))    {        LL sum=0;        for(int i=1;i<=n;++i)        {            scanf("%I64d",a+i);            sum+=a[i];        }        summ=sum;//        cout<<sum<<endl;        sort(a+1,a+1+n,cmp);        if(!(sum%3))        {            for(int i=1;i<=n;i++)            {                printf("%I64d",a[i]);            }            puts("");            continue;        }        bool flag=0;        for(int i=n;i>1;--i)        {            sum-=a[n];            if(!(sum%3))            {                for(int j=1;j<i;j++)                    printf("%I64d",a[j]);                puts("");                flag=1;                break;            }        }        if(flag) continue;        Max=LONG_LONG_MIN;        for(int i=n;i>=1;--i)        {            gen_comb(n,i);        }        if(sizeof(ans)==0)        {            puts("impossible\n");            continue;        }        sort(ans,ans+idx,cmp);        for(int i=0;i<idx;++i)        {            printf("%I64d",ans[i]);        }        puts("");    }    return 0;}

  

数学方法:

// Memory   Time// 1347K     0MS// by : Snarl_jsb// 2014-09-10-11.37#include<algorithm>#include<cstdio>#include<cstring>#include<cstdlib>#include<iostream>#include<vector>#include<queue>#include<stack>#include<map>#include<string>#include<climits>#include<cmath>#define N 10000#define LL long longusing namespace std;LL n;LL a[N];LL ans[N];LL n1,n2,n3;LL q1[N],q2[N],q3[N];bool cmp(LL a,LL b){    return a>b;}int main(){//    freopen("C:\\Users\\ASUS\\Desktop\\cin.cpp","r",stdin);//    freopen("C:\\Users\\ASUS\\Desktop\\cout.cpp","w",stdout);    while(scanf("%d",&n)!=EOF)    {        n1=n2=n3=0;        LL sum=0;        for(LL i=1;i<=n;i++)        {            scanf("%d",&a[i]);            sum+=a[i];            if(a[i]%3==0)            {                q1[++n1]=a[i];            }            else if(a[i]%3==1)                q2[++n2]=a[i];            else                q3[++n3]=a[i];        }        if(sum%3==0)        {            sort(a+1,a+1+n);            for(int i=n;i>=1;--i)            {                printf("%d",a[i]);            }            puts("");            continue;        }        sort(q1+1,q1+1+n1,cmp);        sort(q2+1,q2+1+n2,cmp);        sort(q3+1,q3+1+n3,cmp);        if(sum%3==1)        {            if(n2>=1)            {                n2--;            }            else if(n3>=2)            {                n3-=2;            }            else            {                puts("impossible\n");                continue;            }        }        else if(sum%3==2)        {            if(n1>=2)            {                n1-=2;            }            else if(n2>=1)            {                n2--;            }            else            {                puts("impossible\n");                continue;            }        }        LL idx=0;        for(int i=1;i<=n1;++i)        {            ans[++idx]=q1[i];        }        for(int i=1;i<=n2;++i)        {            ans[++idx]=q2[i];        }        for(int i=1;i<=n3;++i)        {            ans[++idx]=q3[i];        }        sort(ans+1,ans+1+idx,cmp);        for(int i=1;i<=idx;i++)        {            printf("%I64d",ans[i]);        }        puts("");    }    return 0;}

  

数论 - 整除问题 --- 整数集合中找出3的最大倍数