hdu5902,5505——GCD小合集

来源:互联网 发布:网络优化与维护 编辑:程序博客网 时间:2024/06/05 05:47

一次校内比赛中碰到这两个题,有一次加深了对GCD的认识

hdu5902

题目链接

http://acm.split.hdu.edu.cn/showproblem.php?pid=5902

GCD is Funny

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 860    Accepted Submission(s): 227


Problem Description
Alex has invented a new game for fun. There are n integers at a board and he performs the following moves repeatedly:

1. He chooses three numbers a,b and c written at the board and erases them.
2. He chooses two numbers from the triple a,b and c and calculates their greatest common divisor, getting the number d (d maybe gcd(a,b),gcd(a,c) or gcd(b,c)).
3. He writes the number d to the board two times.

It can be seen that after performing the move n2 times, there will be only two numbers with the same value left on the board. Alex wants to know which numbers can left on the board possibly. Can you help him?
 

Input
There are multiple test cases. The first line of input contains an integerT(1T100), indicating the number of test cases. For each test case:

The first line contains an integer n(3n500) -- the number of integers written on the board. The next line contains n integers: a1,a2,...,an(1ai1000) -- the numbers on the board.
 

Output
For each test case, output the numbers which can left on the board in increasing order.
 

Sample Input
341 2 3 442 2 2 255 6 2 3 4
 

Sample Output
1 221 2 3
 

Source
BestCoder Round #87
 

Recommend
wange2014   |   We have carefully selected several similar problems for you:  6022 6021 6020 6019 6018 

题意比较好懂,一个数组每个数任意两两求最大公约数后,把得到的GCD放入数组进行更新。
然后对更新后的数组再次求GCD(一共n-2次操作),输出最后的GCD
题意不难,就是用标记数组多次求GCD的思想比较重要
代码:
#include<iostream>#include<cstdio>#include<cmath>#include<cstring>#include<algorithm>#include<vector>#include<set>#define INF 0x3f3f3f3fusing namespace std;typedef long long ll;int gcd(int x,int y){    return y?gcd(y,x%y):x;}int main(){    int T,n,t;    int i,j,k;    int a[1005],vis[1005]/*标记数组*/;    scanf("%d",&T);    while(T--){        scanf("%d",&n);        for(i=0;i<n;i++){            scanf("%d",&a[i]);        }        memset(vis,0,sizeof(vis));        for(i=0;i<n-1;i++){ ///对原数组中的数两两GCD            for(j=i+1;j<n;j++){                vis[gcd(a[i],a[j])]=1;            }        }        int t=1;    ///标记是否有新的GCD产生        int len=1;        while(t&&len<n-2){  ///一共n-2次操作            t=0;            len++;            for(i=1;i<=1000;i++){   ///对于更新后的数组再次GCD                for(j=0;j<n;j++){                    if(vis[i]&&!vis[gcd(i,a[j])]){                        t=1;                        vis[gcd(i,a[j])]=1;                    }                }            }        }        t=1;        for(i=0;i<=1000;i++){            if(vis[i]){                if(t){                    printf("%d",i);                    t=0;                }                else                printf(" %d",i);            }        }        printf("\n");    }    return 0;}




题目链接
http://acm.split.hdu.edu.cn/showproblem.php?pid=5505

GT and numbers

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 2115    Accepted Submission(s): 546


Problem Description
You are given two numbers N and M.

Every step you can get a new N in the way that multiply N by a factor of N.

Work out how many steps can N be equal to M at least.

If N can't be to M forever,print 1.
 

Input
In the first line there is a number T.T is the test number.

In the next T lines there are two numbers N and M.

T1000,1N1000000,1M263.

Be careful to the range of M.

You'd better print the enter in the last line when you hack others.

You'd better not print space in the last of each line when you hack others.
 

Output
For each test case,output an answer.
 

Sample Input
31 11 22 4
 

Sample Output
0-11
 

Source
BestCoder Round #60
 

Recommend
hujie   |   We have carefully selected several similar problems for you:  6022 6021 6020 6019 6018 

题意:给定n,m两个数,求n乘几次n的因子可以得到m,输出乘法次数,永远得不到输出-1
可以用GCD逐步逼近目标解

代码:

#pragma GCC optimize("03")///适当的加速#include<iostream>#include<cstdio>#include<cmath>#include<cstring>#include<algorithm>#define INF 0x3f3f3f3fusing namespace std;typedef unsigned long long ll;///long long爆了,WAll gcd(ll x,ll y){    return y?gcd(y,x%y):x;}int main(){    int T,t;    ll n,m,ans;    int i,j,k;    scanf("%d",&T);    while(T--){        t=0;        scanf("%llu %llu",&n,&m);        if(n>m||m%n||(n==1&&m!=1)){ ///排除特例            printf("-1\n");            continue;        }        else{            while(n!=m){                ans=gcd(n,m/n);  //每次要乘的最大因子                if(ans==1){//遇到有1的情况,变为特例                    t=-1;                    break;                }                n*=ans;     ///对n进行更新,逐渐接近m                t++;            }            printf("%d\n",t);        }    }    return 0;}
用一组举例分析

Input

6 7776

Output
3

n=6   m=7776   ans=6   

n=6*6 t++

n=36   m=7776   ans=36   

n=36*36 t++

n=1296   m=7779  ans=6

n=1296*6 t++

n=m

对于这道题还有一个坑点就是数据范围

摘一段其他博文的内容:


/****************************************************/

转自:http://blog.csdn.net/queuelovestack/article/details/49210173

出题人的解题思路:

1002 GT and numbers

如果AA大于BB那么显然无解。

考虑把AABB分解质因数。

BB存在AA没有的质因数也显然无解。

对于某一个AA的质因数的次数。为了加速接近BB,它一定是每次翻倍,最后一次的时候把剩下的加上。

那么答案就是最小的kk使得2^{k}*A_{num} \geq B_{num}2kAnumBnum

最后把每个质因数的答案max起来即可。

感觉本场比赛没有trick(雾~),我就打算加入一个很经典的trick:

BB可以刚好等于2^{63}263,这样就要开unsigned long long。

同时我还在题目里特别提醒了“注意M的范围”

可惜仍然有很多选手没有注意。

这里我表示歉意,也希望你们以后可以更加仔细一点。

对于题目的解法,我相信通过出题人的解题报告,多多少少都能明白一点,在此,我也不多说,有不明白的可以留下评论
在此,其实我想说的是,B的定义问题,因为B可以取到263,所以不管是long long,还是__int64都是不够大的,因为它们所能表示的最大值为263-1,所以就如上面的题解所说要用到unsigned,也就是这个原因,我不小心坑害了3个人
可能是看到我用了__int64吧,他们果断用下面这组数据来hack我
1
2 9223372036854775808

然而令我也没想到的是居然还是对的,虽然__int64的变量m无法保存263,但是它会保存成-263,这对于求公约数是没有影响的,而我代码中的n不断变大,就算m为-263,n最终也能成-263,这样就保证了可以判断n==m




0 0