一、模板:
//gcd
int gcd(int a,int b)
{
return b==0?a:gcd(b,a%b);
}
//lcm
typedef long long ll;
ll gcd(ll a,ll b)
{
return b==0?a:gcd(b,a%b);
}
ll lcm(ll a,ll b)
{
return a/gcd(b,a%b)*b;
}
//也可以使用C++自带STL:__gcd()
//快速幂取模(先要知道“先运算再取模”和“先取模再运算”是一致的,所以可以先取模简化数据)
typedef long long ll;
ll speed(ll a,ll b,ll c)
{
ll ans=1;
a%=c;
while(b)
{
if(b&1) ans=(ans*a)%c; //这个地方不能简写成ans*=a%c,这样先算了a%c
b>>=1;
a=(a*a)%c;
}
return ans;
}
且x*y=gcd(x,y)*lcm(x,y);
二、专题练习&题解:
(今天又是迷茫的一天,后面的题难度增加)
1.多个数的最大公约数
多个数就第一个与第二个算,再拿结果和第三个数算,再拿结果和……就行了。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b)
{
return b==0?a:gcd(b,a%b);
}
int main()
{
ll n;
while(cin>>n)
{
ll ans,x;
cin>>ans;
for(ll i=2;i<=n;i++)
{
scanf("%lld",&x);
ans=gcd(ans,x);
}
printf("%lld\n",ans);
}
return 0;
}
2.多个数的最小公倍数
同上
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b)
{
return b==0?a:gcd(b,a%b);
}
ll lcm(ll a,ll b)
{
return a/gcd(b,a%b)*b;
}
int main()
{
ll n;
while(cin>>n)
{
ll ans,x;
cin>>ans;
for(ll i=2;i<=n;i++)
{
scanf("%lld",&x);
ans=lcm(ans,x);
}
printf("%lld\n",ans);
}
return 0;
}
3.快速幂取模
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll speed(ll a,ll b,ll c)
{
ll res=1;
a%=c;
while(b)
{
if(b&1) res=(res*a)%c;
b>>=1;
a=(a*a)%c;
}
return res;
}
int main()
{
ll a,b,c;
ll ans;
while(cin>>a>>b>>c)
{
ans=speed(a,b,c);
cout<<ans<<endl;
}
return 0;
}
4.库特的数学题
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll sp(ll a,ll b)
{
ll ans=1;
while(b)
{
if(b&1)
ans=ans*a%1000000007;
a=a*a%1000000007;
b>>=1;
}
return ans;
}
int main()
{
ll n,N=3;
while(cin>>n)
{ll ans;
ans=6*sp(N,n-1);
cout<<ans%1000000007<<endl;} //这里要注意ans还要再取余一次,防止快速幂取模的结果*6后溢出
return 0;
}
5.LCM&GCD
暴力枚举。因为设x、y,其gcd=a、lcm=b,则xy=ab,所以令tmp=x*y,这样一来当tmp在合法范围内能整除到一个数,且这个数能够满足相应条件,那么就意味着找到了一对组合。详情见代码。
#include <bits/stdc++.h>
using namespace std;
int main()
{
int t;
while(cin>>t)
{
while(t--)
{
long long x,y,ans=0;
cin>>x>>y;
long long tmp=x*y;
for(long long i=x;i<=y;i+=1)
{
if(tmp%i==0)
if(tmp/i>=x && tmp/i<=y&& __gcd(i,tmp/i)==x) //得保证其gcd是x,那么lcm肯定是y
ans++;
}
printf("%d\n",ans);
}
}
return 0;
}
6.人见人爱gcd
这题需要推导一下等式关系。用x=a-y,y=a-x带入lcm=(xy)/gcd,得到x^ 2+y^2=aa-2bgcd(x,y);然后再证出gcd(x,y)=gcd(a,b)即可。这里可以参考一下大佬@nefu_ljw的证明过程(某人想偷懒/大笑):
//如果用cin、cout,需要取消同步流,特别容易超时(/大哭)
#include <bits/stdc++.h>
using namespace std;
int gcd(int a,int b)
{
return b?gcd(b,a%b):a;
}
int main()
{
int t,a,b;
while(scanf("%d",&t)!=-1)
{
while(t--)
{
scanf("%d %d",&a,&b);
printf("%d\n",a*a-2*b*gcd(a,b));
}
}
return 0;
}
7.高木同学的因子
暴力枚举。但为了避免超时,我们需要进行一些优化。求两个数的共同因子个数,可以先求其最大公约数k,然后从1遍历到sqrt(k),再把结果*2即可。注意:完全平方数有两个因子是相同的,所以完全平方和的因子为奇数个,所以若k为完全平方数则cnt-1。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
ll x, y;
cin>>x>>y;
int k= __gcd(x, y);
int cnt=0;
for(int i=1; i<=sqrt(k); i++)
if(k%i==0) cnt++;
if(sqrt(k)*sqrt(k) == k) cout<<cnt*2-1<<endl; //因为int型不保留小数,所以只有完全平方数才相等
else cout<<cnt*2<<endl;
return 0;
}
8.异或方程解的个数
这题需要分析清楚。n-x=n^x,那么就用二进制思考,题目转变成了:当在左边二进制减法、右边二进制半加的条件下,两边的结果相等。则对比二进制串上的每一位,举例:在第k位上,如果n为1,那么在两种运算下,x在该位取0或1都是相等的;如果n为0,则只有x为0两边才相等。所以遇到n在某位为1,则可能性*2.
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n;
while(~scanf("%d",&n))
{
int cnt=0; //计数遇到了多少次1
while(n)
{
if(n&1)
cnt++;
n>>=1;
}
printf("%d\n",1<<cnt);
}
return 0;
}
最后感谢@Havoc.Wei大佬的指导。