第一题:Where do I Turn?
题意:给你3个点A,B,C的坐标,告诉你AB,BC之间要么在一条直线上,要么相互垂直,现在你在B点上,背后是A点,问之后是左转,直行还是右转能到达C点。
题解:通过叉积判断三点关系即可,注意要用long long。
代码:
#include<cstdio>
#include<cstring>
#include<cmath>
#include<set>
#include<algorithm>
using namespace std;
#define LL long long
struct point
{
LL x,y;
} x[3];
LL crossProduct(point a,point b,point c)//向量 ac 在 ab 的方向 顺时针是正
{
return (c.x-a.x)*(b.y-a.y)-(b.x - a.x)*(c.y-a.y);
}
int main()
{
for(int i=0; i<3; ++i)
scanf("%I64d%I64d",&x[i].x,&x[i].y);
if((x[2].y-x[1].y)*(x[1].x-x[0].x)==(x[1].y-x[0].y)*(x[2].x-x[1].x))
puts("TOWARDS");
else if(crossProduct(x[2],x[1],x[0])<0)
puts("RIGHT");
else
puts("LEFT");
return 0;
}
第二题: Effective Approach
题意:给你一个由n个不同数字组成的数列,同时有m次查询,问你在m次查询后,正向查询与逆向查询两种枚举比较的查询方法分别要比较多少次才能完成这m次查询。
题解:因为是n个不同的数字,可以记录数字i在数组中的位置为step[i],则正向查询数字i的比较次数为step[i],而逆向查询数字i的比较测试为n-step[i]+1。
代码:
#include<cstdio>
#include<cstring>
#include<cmath>
#include<set>
#include<algorithm>
using namespace std;
int num[100005];
int step[100005];
int main()
{
int n,m,a;
long long x,y;
x=y=0;
scanf("%d",&n);
for(int i=1;i<=n;++i)
{
scanf("%d",num+i);
step[num[i]]=i;
}
scanf("%d",&m);
for(;m--;)
{
scanf("%d",&a);
x+=step[a];
y+=(n-step[a]+1);
}
printf("%I64d %I64d\n",x,y);
return 0;
}
第三题: Flying Saucer Segments
题意:有n个外星人,分别标号为1~n,同时有3个房间A,B,C,A与B相连,B与C相连,现在外星人都在C房间里,要全部走到A房间中,但是要遵循以下规则:1)一次只能移动一个外星人。2)如果一个外星人要从A到B房间,只有当它的标号是A和B房间中最大的才能完成这次移动。问最小的移动次数是多少。答案对m求余。
题解:类似汉诺塔的变体,设f(n)是把n个外星人从C移动到A所需的最小次数,则f(n)=f(n-1)+1+f(n-1)+1+f(n-1)=3*f(n-1)+2,先把n-1个外星人从C移到A(需要f(n-1)),再把标号最小的从C移到B(需要(1)),接着把A中的n-1个移回C(需要f(n-1)),再把标号最小的从B移到A(需要(1)),最后先把n-1个外星人从C移到A(需要f(n-1))。可以求出f(n)=3^n-1,通过快速幂乘求解即可。
代码:
#include<cstdio>
#include<cstring>
#include<cmath>
#include<set>
#include<algorithm>
using namespace std;
#define LL long long
LL fuc(LL a,LL b,LL c)
{
LL ret=1%c;
a%=c;
for(;b;)
{
if(b&1)
ret=(ret*a)%c;
a=(a*a)%c;
b>>=1;
}
return ret;
}
int main()
{
LL n,m;
scanf("%I64d%I64d",&n,&m);
printf("%I64d\n",(fuc(3,n,m)+m-1)%m);
return 0;
}
第四题: Naughty Stone Piles
题意:求一棵哈夫曼树,但是要求每个点被加次数不能超过k。
题解:贪心。
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define LL long long
LL num[100005],sum[100005];
int main()
{
int n,m,x;
LL summ=0,ans;
sum[0]=0;
scanf("%d",&n);
for(int i=1;i<=n;++i) scanf("%I64d",num+i);
sort(num+1,num+1+n);
for(int i=1;i<=n;++i)
{
sum[i]=sum[i-1]+num[i];
summ+=sum[i];
}
scanf("%d",&m);
for(;m--;)
{
scanf("%d",&x);
if(x==1) printf("%I64d\n",summ-sum[n]);
else
{
LL t=n-1,a=1;
for(ans=0;t>=0;t-=a)
{
ans+=sum[t];
a*=x;
}
printf("%I64d\n",ans);
}
}
return 0;
}
第五题:Anniversary
题意:从l到r这r-l+1个数字中任意选取k个数字作为一个集合xi,对于每个集合xi,设yi为以xi集合中的数字为下标的斐波那契数的最大公约数,问max{yi}是多少,答案对m求余。
题解:根据斐波那契最大公约数定理,gcd(fib(a),fib(b))=fib(gcd(a,b)),且斐波那契数列单调递增,则题目简化为求一个集合xi使得这个集合的最大公约数最大。设求解的最大公因数为idx,则idx满足r/idx-(l-1)/idx>=k,即在[l,r]范围内有k个以上idx的倍数,不断枚举idx即可。第idx个斐波那契数可以通过矩阵快速幂乘求解。
代码:
#include<cstdio>
#include<cstring>
#include<cmath>
#include<set>
#include<algorithm>
using namespace std;
#define LL long long
struct matrix
{
LL b[2][2];
};
LL m;
matrix quickpow(matrix a,matrix b)//矩阵乘法
{
matrix ret;
for(int i=0; i<=1; ++i)
{
for(int j=0; j<=1; ++j)
{
ret.b[i][j]=0;
for(int k=0; k<=1; ++k)
{
ret.b[i][j]=(ret.b[i][j]+(a.b[i][k]*b.b[k][j]))%m;
}
}
}
return ret;
}
LL check(LL n)//矩阵快速幂乘
{
matrix a= {{{1,1},{1,0}}};
matrix b= {{{1,0},{0,1}}};
for(; n;)
{
if(n&1)
{
b=quickpow(a,b);
}
n=n>>1;
a=quickpow(a,a);
}
return b.b[1][0];
}
int main()
{
LL l,r,k,t;
scanf("%I64d%I64d%I64d%I64d",&m,&l,&r,&k);
LL idx=r/k;
for(;idx>1;)
{
if(r/idx-(l-1)/idx>=k) break;
idx=r/(r/idx+1);
}
printf("%I64d\n",check(idx));
return 0;
}