青蛙的约会 扩展欧几里得法求解同余方程
题意:两只青蛙,沿着一条首位相连的数轴在跳,数轴长度为L,A在x处,一次可以跳m米,B在y处,一次可以跳n米,问跳了几次后碰面。
移项得 即(m-n)*t+k*L=y-x
注意y-x必须大于0
我代码中
运用extgcd(m-n,L,a,k) 得到的a是 的解,要得到原方程的解,还需要
才是的解
以及(y-x)无法被gcd(m-n,L)整除的话,无解
#include<stdio.h>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
LL x,y,m,n,L;
LL extgcd(LL a,LL b,LL &x,LL &y) //返回gcd(a,b) ax+by=1
{
if(a==0&&b==0) return -1;
if(b==0) {x=1;y=0;return a;}
LL d=extgcd(b,a%b,y,x);
y=y-a/b*x;
return d;
}
LL mod_inverse(LL a,LL n)
{
LL x,y;
LL d=extgcd(a,n,x,y); //由扩展欧几里得得到一个特解x
if(d==1) return (x%n+n)%n; //+n 防负数。。 x变为最小非负整数解
else return -1;
}
int main()
{
// if(x<0) x=L+x;
// if(y<0) y=L+y; 原先我这么写可真是傻逼啊,我应该让y-x>0,同步改
//设时间为t,则两个青蛙的位置分别为(x+mt)mod L、(y+nt) mod L,相遇即是(x+mt)%L=(y+nt)%L,即(m-n)*t+k*L=y-x
LL x,y,m,n,L;
while(cin>>x>>y>>m>>n>>L)
{
if(m<n) swap(m,n),swap(x,y); //这行代码是必要的 extgcd函数是必须的
LL a,k;
LL c=y-x;
LL d=extgcd(m-n,L,a,k);
LL r=mod_inverse((m-n)/d,L/d);
if(c%d) cout<<"Impossible"<<endl; //c不是d的倍数,则无解
else cout<<((r*c/d)%(L/d)+L/d)%(L/d)<<endl; // (a*c/d)%(L/d)+(L/d)也对 这个是最小正答案
}
return 0;
}
题意:for (variable = A; variable != B; variable += C) 这个循环在mod 2^k下执行了几次
-> -> extgcd(c,2^k,x,y)
注意点 2^k会超int。 LL mod=1<<k , LL mod=LL(1<<k). LL mod=1LL<<k 或者 LL mod=(LL)1<<k ,要先把1转换成LL型
话说我经常明明想到要LL,但是却在中间过程死掉。最遗憾的一次是扇贝杯,最难受的一次是队友写的一道线段树,传参数的时候中间值爆int了,对比了正确代码怎么都找不出错误,最后问了sdn大佬一眼指出问题_(:з」∠)_
#include<stdio.h>
#include<iostream>
using namespace std;
typedef long long LL;
LL extgcd(LL a,LL b,LL &x,LL &y) //返回gcd(a,b) ax+by=1
{
if(a==0&&b==0) return -1;
if(b==0) {x=1;y=0;return a;}
LL d=extgcd(b,a%b,y,x);
y=y-a/b*x;
return d;
}
LL mod_inverse(LL a,LL n)
{
LL x,y;
LL d=extgcd(a,n,x,y);
if(d==1) return (x%n+n)%n;
else return -1;
}
int main()
{
LL A,B,C,k;
while(cin>>A>>B>>C>>k&&!(!A&&!B&&!C&&!k)) //不能四个同时为0
{
//if(C==0&&A!=B) {cout<<"FOREVER"<<endl; continue;}
LL x,y;
// LL mod=1LL<<k; 这样OK
LL mod=(LL)1<<k; //(LL)(1<<k)也是错的
LL d=extgcd(C,mod,x,y);
if((B-A)%d) {cout<<"FOREVER"<<endl; continue;}
else
{
LL r=mod_inverse(C/d,mod/d);
cout<<(r*(B-A)/d%(mod/d)+mod/d)%(mod/d)<<endl; //r和x都可以
}
}
return 0;
}
题意:在[a,b]区间,素数的占比。注意rounded to two decimal digits是要四舍五入到小数点后第二位
UVA 10200 我的题解 hin奇怪我这题的vjudge提交记录都没了
题意:Fn是所有分母<=n,分子分母互素的分数的集合。问Fn的大小是多少
思路:有O - GCD - Extreme (II)的铺垫,这道题就很简单
Fn是Fn-1 加上以n为分母的数,所以
#include<stdio.h>
#include<iostream>
using namespace std;
const int N=1e6+10;
typedef long long LL;
int euler[N];
LL num[N];
void gete()
{
for(int i=2;i<N;++i)
euler[i]=i;
for(int i=2;i<N;++i)
{
if(euler[i]==i) //说明i是素数
{
for(int j=i;j<N;j+=i)
euler[j]=euler[j]/i*(i-1);
}
}
// for(int i=2;i<100;++i)
// cout<<euler[i]<<endl;
}
void getN()
{
num[2]=euler[2];
for(int i=3;i<N;++i)
num[i]=num[i-1]+euler[i];
}
int main()
{
gete();
getN();
int n;
while(cin>>n&&n)
{
cout<<num[n]<<endl;
}
return 0;
}
UVA 11752 题目链接打不开了 但我学到的还是要记录的
题意:super power numbers指的是可以表示成两个整数的次幂形式的数,如64=4^4 64=8^2。要求输出[1,2^64-1]范围内所有的super power numbers
64=2^6=2^(2*3) 可知要想成为超级数,得是一个数的合数次幂,易知这个合数次幂大于等于4(最小合数),小于等于64(最小的底数就是2)
所以对底数遍历,指数的上界是upper=ceil(64*log(2)/log(i));小于该上界的合数次幂都是超级数
#include<iostream>
#include<set>
#include<math.h>
#include<stdio.h>
using namespace std;
typedef long long LL;
const int N=70;
int tag[70];
int prime[70];
int cnt;
int num;
int compo[70];
set<LL> s;
void getp()
{
tag[0]=tag[1]=1;
for(int i=2;i<N;++i)
{
if(!tag[i])
prime[++cnt]=i;
for(int j=1;j<=cnt&&prime[j]*i<N;++j)
{
tag[prime[j]*i]=1;
if(i%prime[j]==0) break;
}
}
for(int i=4;i<64;++i) //记录4-64之间的所有合数
if(tag[i]) compo[++num]=i;
}
int main()
{
// LL m=1<<64; 不知道为何这个值为0 当然是因为我爆Int啦,气哭
getp();
s.clear();
s.insert(1);
int L=1<<16;
for(int i=2;i<=L;++i) //最大只能是(2^16)^4所以到这
{
//cout<<i<<endl;
int upper=ceil(64*log(2)/log(i));
for(int j=1;j<=num&&compo[j]<upper;++j) //未加j<=num,导致有些0 2^0=1,但是对答案应该没有影响
{
LL x=(LL) pow(i,compo[j]);
s.insert(x);
}
}
//s.erase(s.begin());
for(set<LL>::iterator it=s.begin();it!=s.end();++it)
cout<<*it<<endl;
return 0;
}