输入2个正整数x0,y0(2<=x0<100000,2<=y0<=1000000),求出知足下列条件的P,Q的个数。node
条件:1.P,Q是正整数;
2.要求P,Q以x0为最大公约数,以y0为最小公倍数。c++试求: 知足条件的全部可能的两个正整数的个数。算法
每一个测试文件包含不超过5组测试数据,每组两个正整数x0和y0(2<=x0<100000,2<=y0<=1000000)。数组
对于每组输入数据,输出知足条件的全部可能的两个正整数的个数。函数
下面是对样例数据的说明:测试
输入3 60ui
此时的P Q分别为:spa
3 60
15 12
12 15
60 3code因此,知足条件的全部可能的两个正整数的个数共4种。递归
#include<bits/stdc++.h> using namespace std; int gcd(int a,int b){ if(b==0) return a; return gcd(b,a%b); } int main(){ int x,y; while(~scanf("%d%d",&x,&y)){ int ans=0; int mul=x*y; for(int i=x;i<=y;i++){ if(mul%i!=0) continue; int k=mul/i; if(x==gcd(i,k)) ans++; } cout<<ans<<endl; } return 0; }
定理:两个整数的最大公约数等于其中较小的那个数和两数相除余数的最大公约数。最大公约数(Greatest Common Divisor)缩写为GCD。
gcd(a,b) = gcd(b,a mod b) (不妨设a>b 且r=a mod b ,r不为0)
证实 :a能够表示成a = kb + r(a,b,k,r皆为正整数,且r<b),则r = a mod b
假设d是a,b的一个公约数,记做d|a,d|b,即a和b均可以被d整除。
而r = a - kb,两边同时除以d,r/d=a/d-kb/d=m,由等式右边可知m为整数,所以d|r
所以d也是b,a mod b的公约数
假设d是b,a mod b的公约数, 则d|b,d|(a-k*b),k是一个整数。
进而d|a.所以d也是a,b的公约数
所以(a,b)和(b,a mod b)的公约数是同样的,其最大公约数也必然相等,得证。
如下是gcd算法C++实现代码:
int Gcd(int a, int b) { if(b == 0) return a; return Gcd(b, a % b); }
#include<bits/stdc++.h> #define int long long /*无论32位仍是64位的,int都是4个字节,一个字节8位,即32位。 long long 都是8个字节,就是64位,这句话的做用就是将原来的int_32 型 改为int_64型, 在一些预编译里面还会出现 #define _int64 long long的语句,c99标准以后,64位的int都用long long 来表示,这里能够理解为处理标准兼容的问题。 */ #define N 500005 using namespace std; const int Mod=1e9+7;//科学计数法 struct node{ int x, y; }a[N];//定义结构体的同时,定义大小为N的结构体数组。 inline bool cmp(node aa,node bb) { return aa.y*bb.x>aa.x*bb.y; //避免精度问题因此采用交叉相乘的方式比较大小 } inline int ksm(int x,int y)//x是底数,y是指数 {//快速求模运算。 int ans1=1; while (y) { if (y&1) //逐位“与”运算,经过和1相与,保留最后一位 { ans1=1ll*ans1*x; ans1=ans1%Mod;//ans1记录前面每次翻倍求模结果的乘积再求模 } /*经过乘以1ll,将等号右边的精度提升到long long ,低精度向高精度转化,避免中间结果溢出范围,右边的ans如今是64位的int,原来32位的int型 10位数字,long long 19位数字, 1e+9是9位数字, 因此是32位仍是64位都不会超出范围。 */ y>>=1;//右移1位至关除以2,类比十进数,右移一位至关于除以10,同理左移,是乘以相应的进制基数。 x=1ll*x*x%Mod;//x中记录每次翻倍的求模的结果。 } return ans1; } signed main() { int n; scanf("%lld",&n); for (int i=1;i<=n;i++) scanf("%lld%lld",&a[i].x,&a[i].y);//注意结构体的输入方式。 sort(a+1,a+n+1,cmp);//i=1开始,因此起始位置为a+1 for (int i=1;i<=n;i++) printf("%lld\n",a[i].y*ksm(a[i].x,Mod-2)%Mod);//分数求模的定理转换。 return 0; }
1.在 c/c++ 中,为了解决一些频繁调用的小函数大量消耗栈空间(栈内存)的问题,特别的引入了 inline 修饰符,表示为内联函数。
栈空间就是指放置程序的局部数据(也就是函数内数据)的内存空间。
在系统下,栈空间是有限的,假如频繁大量的使用就会形成因栈空间不足而致使程序出错的问题,如,函数的死循环递归调用的最终结果就是致使栈内存空间枯竭。
2.inline 的使用是有所限制的,inline 只适合涵数体内代码简单的函数使用,不能包含复杂的结构控制语句例如 while、switch,而且不能内联函数自己不能是直接递归函数(即,本身内部还调用本身的函数)。
3.inline 函数仅仅是一个对编译器的建议,因此最后可否真正内联,看编译器的意思,它若是认为函数不复杂,能在调用点展开,就会真正内联,并非说声明了内联就会内联,声明内联只是一个建议而已。
慎用inline!!!
内联是以代码膨胀(复制) 为代价,仅仅省去了函数调用的开销,从而提升函数的执行效率。
若是执行函数体内代码的时间,相比于函数调用的开销较大,那么效率的收获会不多。另外一方面,每一处内联函数的调用都要复制代码,将使程序的总代码量增大,消耗更多的内存空间。
因此上式又可继续转化为\(((Vmodp)*(e^{-1}modp))modp=V*(e^{p-2}modp)modp\)
(由于V<p因此mod后不变)
if((x&1)==1) printf("奇数"); else if((x&1)==0) printf("偶数");