2018年全国多校算法寒假训练营练习比赛(第三场)题解

本文精选了几道算法竞赛题目并提供了详细的解题思路与代码实现,涵盖了斯特林公式应用、中国剩余定理变形、博弈论策略及容斥原理等多个方面。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

传送门:第三场



A.不凡的大夫


题目大意:

求n!的在8进制下的位数是多少位。


思路:

求 n!在8进制下的位数即求 log8(n!),由于 n! 太大没法直接求,可以用斯特林公式来代替。斯特林公式:,利用对数函数的一些性质可以化简上述式子,求解 log8() 也可以用换底公式来做。需要注意的是,当 n=0 时会出错,需要特判。


代码:

#include<stdio.h>
#include<math.h>
#include<string.h>
int main()
{
	int i,t,n,ans;
	double PI=atan(1)*4;
	double e=exp(1);
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d",&n);
		if(n==0)
		{ //n=0时特判 
			printf("1\n");
			continue;
		}
		//利用斯特林公式求 log8(n!) 
		ans=log(sqrt(2*n*PI))/log(8)+n*log((double)n/e)/log(8);
		printf("%d\n",ans+1);
	}
	return 0;
}


B.一个小问题


题目大意:

假设同余方程组为:
    x=r1(mod a1)
    x=r2(mod a2)
    ………………
    x=rn(mod an)
求此方程组的最小非负整数解


思路:

该题为求解一元线性同余方程,与中国剩余定理不同的是该题不要求 r 之间两两互素。直接套用模板即可。需要注意的是,结果可能超过整形,所以要用 long long。


代码:

#include<stdio.h>
#include<string.h>
typedef long long LL;

LL n,a[100010],r[100010];

LL exGcd(LL a,LL b,LL &x,LL &y)
{ //拓展欧几里得 
    LL r,t;
    if(b==0)
    {
        x=1;y=0;
        return a;
    }
    r=exGcd(b,a%b,x,y);
    t=x;
    x=y;
    y=t-a/b*y;
    return r;
}

LL solve()
{ //求解一元线性同余方程 
	LL i,c,d,t,x,y;
	for(LL i=1;i<n;i++) 
	{
		c=r[i]-r[i-1];
		d=exGcd(a[i-1],a[i],x,y);
		if(c%d!=0) return -1; //无解
		t=a[i]/d;
		x=x*(c/d);
		x=(x%t+t)%t;
		r[i]=a[i-1]*x+r[i-1];
		a[i]=a[i-1]*(a[i]/d);
	}
	return r[n-1];
}

int main()
{
	LL i,j,ans;
	scanf("%lld",&n);
	for(i=0;i<n;i++) scanf("%lld%lld",&a[i],&r[i]);
	ans=solve();
	printf("%lld\n",ans);
	return 0;
}


D.小牛VS小客


题目大意:
小牛和小客玩石子游戏,他们用n个石子围成一圈,小牛和小客分别从其中取石子,谁先取完谁胜,每次可以从一圈中取一个或者相邻两个,每次都是小牛先取,请输出胜利者的名字。


思路:

自己写出了 n<=8 时候的结果,推测 n>2 的时候小客赢,其余小牛赢。


代码:



E.进击吧!阶乘


题目大意:

给定一个整数N(0≤N≤10000),求取N的阶乘。


思路:

直接用 python做的,5行代码搞定。


代码:略。



F.小牛再战


题目大意:

共有N堆石子,已知每堆中石子的数量,两个人轮流取石子,每次只能选择N堆石子中的一堆取一定数量的石子(最少取一个),取过子之后,还可以将该堆石子中剩余的石子随意选取几个放到其它的任意一堆或几堆上。等哪个人无法取子时就表示此人输掉了游戏。注意:一堆石子没有子之后,就不能再往此处放石子了。

假设每次都是小牛先取石子,并且游戏双方都绝对聪明,现在给你石子的堆数、每堆石子的数量,请判断出小牛能否获胜。


思路:

网上有种思路是将除石子数为 1 的之外的数相异或,看结果是否为 0。不过还没想明白,初步看和尼姆博弈题目类似。


代码:

#include<stdio.h>
int main()
{
    int i,n,a,f;
    while(~scanf("%d",&n)&&n)
    {
        f=0;
        for(i=0;i<n;i++)
        {
            scanf("%d",&a);
            if(a!=1) f^=a;
        }
        if(f) printf("Win\n");
        else printf("Lose\n");
    }
    return 0;
}


G.大水题


题目大意:

给出一个数n,求1到n中,有多少个数不是2 5 11 13的倍数。


思路:

容斥原理,奇加偶减。


代码:

#include<stdio.h>
#include<string.h>
typedef long long LL;
int main()
{
	LL a,b,c,d,n,ans;
	while(~scanf("%lld",&n))
	{
		a=n/2;
		b=n/5;
		c=n/11;
		d=n/13;
		ans=a+b+c+d-(n/10)-(n/22)-(n/26)-(n/55)-(n/65)-(n/143)+(n/110)+(n/130)+(n/286)+(n/715)-(n/1430);
		printf("%lld\n",n-ans);
	}
	return 0;
}


I.三角形


题目大意:
给你一个三角形的顶点A,B,C的坐标(坐标都为整数),请求出三角形的面积,三角形内的点的个数以及边AB、BC和AC边上的点的个数(不包括顶点ABC)


思路:

面积可以用海伦公式或者向量法求;GCD求线段上整点;皮克定理求内部整点。注意因为该题三角形边长最大为 1e6,所以利用海伦公式时会出错,得用向量法求。另记得用 long long .


代码:

#include<stdio.h> 
#include<string.h>
#include<math.h>
typedef long long LL;

LL gcd(LL a,LL b)
{ //求最大公约数 
	if(b==0) return a;
	else return gcd(b,a%b);
}

int main()
{
	LL x1,x2,x3,y1,y2,y3,ans1,ans2;
	double area;
	while(~scanf("%lld",&x1)&&x1!=-1)
	{
		scanf("%lld%lld%lld%lld%lld",&y1,&x2,&y2,&x3,&y3);
		area=fabs(x1*y2+x2*y3+x3*y1-x1*y3-x2*y1-x3*y2)/2; //利用向量求面积 
		//三角形边上的点的个数 
		ans2=gcd(fabs(x1-x2),fabs(y1-y2))+gcd(fabs(x1-x3),fabs(y1-y3))+gcd(fabs(x3-x2),fabs(y3-y2));
		ans1=area-ans2/2+1; //三角形内点的个数 
		printf("%.1lf %lld %lld %lld %lld\n",area,ans1,gcd(fabs(x1-x2),fabs(y1-y2))-1,gcd(fabs(x3-x2),fabs(y3-y2))-1,gcd(fabs(x1-x3),fabs(y1-y3))-1);
	}	
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值