一次校内比赛中碰到这两个题,有一次加深了对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
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 n−2 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?
The first line contains an integer n (3≤n≤500) -- the number of integers written on the board. The next line contains n integers: a1,a2,...,an (1≤ai≤1000) -- the numbers on the board.
3 4 1 2 3 4 4 2 2 2 2 5 5 6 2 3 4
1 2 2 1 2 3
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<vector>
#include<set>
#define INF 0x3f3f3f3f
using 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;
}
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
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 .
In the next T lines there are two numbers N and M .
T≤1000 , 1≤N≤1000000 , 1≤M≤263 .
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.
3 1 1 1 2 2 4
0 -1 1
代码:
#pragma GCC optimize("03")///适当的加速
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define INF 0x3f3f3f3f
using namespace std;
typedef unsigned long long ll;///long long爆了,WA
ll 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
如果A大于B那么显然无解。
考虑把A和B分解质因数。
若B存在A没有的质因数也显然无解。
对于某一个A的质因数的次数。为了加速接近B,它一定是每次翻倍,最后一次的时候把剩下的加上。
那么答案就是最小的k使得2k∗Anum≥Bnum。
最后把每个质因数的答案max起来即可。
感觉本场比赛没有trick(雾~),我就打算加入一个很经典的trick:
B可以刚好等于263,这样就要开unsigned long long。
同时我还在题目里特别提醒了“注意M的范围”
可惜仍然有很多选手没有注意。
这里我表示歉意,也希望你们以后可以更加仔细一点。
对于题目的解法,我相信通过出题人的解题报告,多多少少都能明白一点,在此,我也不多说,有不明白的可以留下评论2 9223372036854775808