竞赛地址:https://ac.nowcoder.com/acm/contest/3674#question
全部题解地址:https://ac.nowcoder.com/discuss/361704?type=101&order=0&pos=6&page=0
A.The GCD of Fibonacci Numbers(斐波那契数列性质)
题目大意:
给你两个数字m,n分别代表斐波那契数列的第m、n项,求这两个数的最大公约数。
解题思路:
本题用到了斐波那契数列的一个性质,gcd(Fn,Fm)=Fgcd(n,m) 以及斐波那契数列的通项公式:
AC代码:
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<set>
#include<string>
#include<vector>
#include<stack>
#include<queue>
#define PI 3.1415926
typedef long long ll;
using namespace std;
ll Q;
ll x,y,temp;
ll fib(ll n)
{
const double d = sqrt(5);
return floor((pow((1+d)/2, n) - pow((1-d)/2, n))/d + 0.5);
}
ll Euclid_GCD(ll a, ll b)
{
return b?Euclid_GCD(b, a%b):a;
}
int main()
{
ll t=0;
cin>>t;
while(t--)
{
ll a=0,b=0;
cin>>a>>b;
Q=Euclid_GCD(a,b);
cout<<fib(Q)<<endl;
}
return 0;
}
斐波那契数列其余性质(来自百度)
F.Kuangyeye’s Game(几何+思维)
题目大意:
给你几个点的坐标(x,y),请判断他们是不是在一条直线上,注意,几个点中可能有重复的,也就是说可能存在连续多个坐标相同的点。
题目分析:
在同一条直线上的点他们的斜率相同,也就是说y的差值比上x的差值相同。但是要注意一点,当连续几个点的坐标相同时,不能直接算x,y的差值,因为0不能做除数。
AC代码:
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<set>
#include<string>
#include<vector>
#include<stack>
#include<queue>
#define PI 3.1415926
typedef long long ll;
using namespace std;
int main()
{
int n=0;
static int x[1010]={0};
static int y[1010]={0};
cin>>n;
for(int i=0;i<n;i++)
{
scanf("%d%d",&x[i],&y[i]);
}
for(int i=0;i<n-2;i++)
{
if(x[i]!=x[i+1]&&y[i]!=y[i+1]&&x[i+1]!=x[i+2]&&y[i+1]!=y[i+2])
//不存在连续的坐标相同的点
{
if((double)(y[i]-y[i+1])/(double)(x[i]-x[i+1])!=(double)(y[i+1]-y[i+2])/(double)(x[i+1]-x[i+2]))
{
cout<<"No"<<endl;
return 0;
}
}
else
continue;
}
cout<<"Yes"<<endl;
return 0;
}
G.Buying Keys(思维+贪心)
题目大意:
钥匙三块钱一把,十块钱三把,小明有一定数量的钱,问怎么样在把钱花完的前提下配最少数量的钥匙,如果钱无论如何都花不完,输出orz;
题目分析:
就是一个贪心的思想,先紧着十块钱三把的方式配。如果小明的钱不是10的整倍数,那么就三块一把这样配,直到小明的钱小于3或者成为10的倍数,如果小明剩余的钱不为0,那么输出orz。
AC代码:
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<set>
#include<string>
#include<vector>
#include<stack>
#include<queue>
#define PI 3.1415926
typedef long long ll;
using namespace std;
int main()
{
ll n=0,N=0,t=0;
cin>>n;
N=n;
if(n%10==0)
{
n/=10;
n*=3;
cout<<n<<endl;
return 0;
}
else
{
while(n%10!=0&&n>=3)
{
n-=3;
t++;
}
if(n%10==0)
{
n=n/10*3+t;
cout<<n<<endl;
return 0;
}
if(n<3&&n!=0)
{
cout<<"orz"<<endl;
return 0;
}
if(n==0)
{
cout<<t<<endl;
return 0;
}
}
}
H.Dice(概率+思维)
题目大意:
摇n轮骰子,每一次摇骰子你获胜的概率都是50%,第一轮你下的注为1,如果第一局你输了,那么下一次你下的注就是上一轮的两倍。如果你赢了,你就见好就收,结束游戏。问你赢钱的概率是多大。
题目分析:
如果你摇n次骰子,则每一轮下的注的值为2^(n-1),(即1,2,4,8……),由此可见,你只要赢一次,你就能赢钱(因为你懂的见好就收)。因此,咱们要算的是你这n局中每一局都输的概率,再用1减去这个概率就好,注意保留四位小数。而每一局都输的概率为0.5 ^ n。
AC代码:
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<set>
#include<string>
#include<vector>
#include<stack>
#include<queue>
#define PI 3.1415926
typedef long long ll;
using namespace std;
int main()
{
int t=0;
cin>>t;
double ans;
while(t--)
{
ans=0;
int n=0;
cin>>n;
//n++;
while(n>=1)
{
ans+=pow(0.5,n);
n--;
}
printf("%.4lf\n",ans);
}
return 0;
}
J.Fake Nim(思维)
题目描述:
有n堆糖果,每一堆都有各自的数量,DaDa一次能买一堆糖中的偶数个,TuTu一次能买一堆糖中的奇数个,如果商店中的每一堆糖果的个数都小于2,则DaDa就无法购买。谁买走商店中的最后一颗糖谁就获胜,现在DaDa先去买,问谁最后能获胜?
题目分析:
如果一堆糖有k个,假如k是偶数,则TuTu可以买k-1个糖,使得这一堆只剩下1个糖,从而造成DaDa无法再买这一堆糖;假如k是奇数,则TuTu可以把它们全部买走。由上述分析可知,因为DaDa是先手,所以当只有一堆糖且这一堆糖的个数为偶数时DaDa获胜,其余情况均是TuTu获胜。
AC代码:
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<set>
#include<string>
#include<vector>
#include<stack>
#include<queue>
#define PI 3.1415926
typedef long long ll;
using namespace std;
int main()
{
int n=0;
cin>>n;
static ll a[50010]={0};
for(int i=0;i<n;i++)
{
scanf("%lld",&a[i]);
}
if(n==1&&a[0]%2==0)
cout<<"DaDa"<<endl;
else
cout<<"TuTu"<<endl;
return 0;
}
L.Special number(质数判断+特殊情况)
题目大意:
给你一个闭区间的两个端点,问在这个闭区间内有多少个因数不超过3个数的数。
题目分析:
因数不超过3个,则其因数一定为1个或者2个。质数只有两个因数(1和它本身),1只有一个因数1。所以本题要做的就是判断这个区间内有多少个质数,如果区间里面有1,则1也算进去。注意一点,0这个数比较特殊,它没有因数,所以不算题目中所描述的Special number。
AC代码:
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<set>
#include<string>
#include<vector>
#include<stack>
#include<queue>
#define PI 3.1415926
typedef long long ll;
using namespace std;
int main(){
ll m;
ll i;
ll k;
ll l=0,r=0,ans=0;
static ll a[100010]={0};
cin>>l>>r;
for(ll i=l;i<=r;i++)
a[i]=i;
for(ll j=l;j<=r;j++)
{
k=(ll)sqrt( (double)a[j] );
for(i=2;i<=k;i++)
if(a[j]%i==0)
break;
if(i>k&&a[j]!=0)//所有质数还有1,0不算,因为0不能做除数
ans++;
}
cout<<ans<<endl;
return 0;
}
M.XOR sum(异或的应用)
题目大意:
给你一个闭区间的左右端点,请你求一下这个闭区间内所有数字相异或的值。
题目分析:
目前不太理解,日后补。如果有大佬有好的见解,欢迎提出。
经过GX大佬的指点好像明白了点。数字的异或有一个规律,从0开始,每四个数字的异或结果为0。而代码中也正是利用了这个规律,进而可以求出任意给定闭区间【A,B】中各项数字的异或。
AC代码:
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<set>
#include<string>
#include<vector>
#include<stack>
#include<queue>
#define PI 3.1415926
typedef long long ll;
using namespace std;
int main() {
long long A,B;
cin >> A >> B;
long long a=4-A%4, b=B%4, n=0;
for(long long i=A; i<A+a; i++) n=n^i;
for(long long i=B-b; i<=B; i++) n=n^i;
cout << n << endl;
return 0;
}