牛客多校训练8部分题解

E  Rise of Shadows 

题意:

输入一个数,如果既是闰年又是素数输出yes,否则输出no。

题解:

签到题水水水, 易知闰年一定不是素数,所以全部输出no。

代码:

#include<iostream>
using namespace std;
int main(){
	int t;
	cin>>t;
	while(t--){
		int a;
		cin>>a;
		cout<<"no"<<endl;
	}
    return 0;
} 

A Ares, Toilet Ares

题意:

一个竞赛中有n道题,Toilet-Ares本可以解决所有的问题。为保证公平,比赛更换了n-m道题,增强了a道题,Toilet-Ares可以自己解决这a道题。他有k次机会去厕所,每一次有y/z的失败概率获得x行代码,集齐所有代码可以做出第k题。保证∑x=l.求他最终可以通过的题目数量,对4933取模。

题解:

考察对分数取模(逆元)。思路是用a加上k次去厕所都成功的概率之积,也就是 \, a+\prod \left ( 1-y\underset{i}{}/z\underset{i}{} \right ),然后再对4933取模。一个坑点在于x[i]是可能为0的,此时就不需要乘上它成功的概率,需要特判。

代码:

#include<iostream>
using namespace std;
#define ll long long
const int maxn=100005;
int x[maxn],y[maxn],z[maxn];

int mod = 4933;
ll binaryPow(ll a, ll b){
	ll ans = 1;
	while(b > 0){
		if(b & 1){
			ans = ans * a % mod;
		}
		a = a * a % mod;
		b >>= 1; 
	} 
	return ans;
}

ll inv(ll a,ll b)  // a为分子,b为分母 对mod取模
{
    return (a*binaryPow(b,mod-2))%mod;
}


int main(){
	int n,m,k,a,l;
	cin>>n>>m>>k>>a>>l;
	unsigned long long temzi=1;
	unsigned long long temmu=1;
	for(int i=0;i<k;i++){
		cin>>x[i]>>y[i]>>z[i];
		if(x[i]!=0){
			temzi=((z[i]-y[i])%mod*(temzi%mod))%mod;
			temmu=(z[i]%mod)*(temmu%mod)%mod;
		}
		
	}
	cout<<(inv(temzi,temmu)+a%mod)%mod<<endl;
	
}

D OR

题意:

已知长度为n-1的两个序列b,c。要求构造一个a序列,满足b_i = a_{i-1} |a_i  ,  \ c_i = a_{i-1} + a_i ,其中2\le i \le n。求符合条件的a_i序列有多少种。

题解:

从比特位的角度考虑,每一个b_ic_i 都会对a_i 有限制作用。若nb,nc分别表示b、c的最低比特位,d、e表示a_{i-1}a_i的最低比特位,则有

nb=0,nc=0\Rightarrowd=0,e=0;

nb=1,nc=0\Rightarrowd=1,e=1;

nb=1,nc=1\Rightarrowd=1,e=0或d=0,e=1; 

nb=0,nc=1\Rightarrow不存在 

等结论,可以依次枚举a可能的取值,最后统计,详细思路在代码和注释中也有解释。(参考逆十字dalao。)

  

代码:

#include<iostream>
using namespace std;
int b[100005],c[100005];
int f[35];//f记录a[i]的二进制,0和1都可以取则表示为2 
int main(){
	int n;
	scanf("%d",&n);
	for(int i=2;i<=n;i++)scanf("%d",&b[i]);
	for(int i=2;i<=n;i++)scanf("%d",&c[i]);
	for(int i=0;i<30;i++)f[i]=2;//初始化0和1都可以取 
	for(int i=2;i<=n;i++){
		for(int j=0;j<30;j++){
			int nb=(b[i]>>j)&1;//b[i]二进制的第j位 
			int nc=c[i]&1;//c[i]二进制的第j位 
			//记改变前的f[i]为 f前,改变后的为 f后 
			
			if(nb==0){//必有nc=0,f前=0,f后=0,若不满足则结束程序 
				if(nc==0){
					if(f[j]==1)return printf("0\n"),0;
					f[j]=0;c[i]>>=1;
				} 
				else return printf("0\n"),0;	
			}
			else{
				if(nc==0){//nc=0,nb=1,则 f前=f后=1 
					if(f[j]==0) return printf("0\n"),0;
					f[j]=1;c[i]>>=1;c[i]--;//减去f前+f后的进位 
					if(c[i]<0)return printf("0\n"),0;
				}
				else{//nc=1,nb=1,则 f前 f后,分别为0、1 
					if(f[j]!=2){
						f[j]=1-f[j];
					} 
					c[i]>>=1;
				} 			
			}
		} 
		if(c[i]!=0) return printf("0\n"),0;
	} 
	long long ans=1;
	for(int i=0;i<30;i++){
		if(f[i]==2)ans<<=1;
	}
	printf("%lld\n",ans);
	return 0;
}

K  Yet Anther Problem About Pi 

题意:

在二维坐标上,有网格,给定路程为π,输入w,d表示横线之间的距离、竖线之间的距离。求最多能横跨多少个格子?

题解:

跨格子只需要在交叉的地方,画一个半径为极小的圆○。有两种走法:(补图.......

根据题上说明,w,d最小为0.1,所有只需要遍历每一种走法并且维护最大值即可。

代码:

#include<bits/stdc++.h>
using namespace std;
 
const double pi=acos(-1);
 
int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        double w,d,a,b;
        scanf("%lf%lf",&w,&d);
        a=min(w,d);//走直线
        b=sqrt(w*w+d*d);//走斜线
        int ans=4+int(pi/a)*2;
        for(int i=0;i<=50;i++){
            if(pi-i*a>=0)
            ans=max(ans,4+i*2+3*int((pi-i*a)/b));
            else break;
        }
        for(int i=0;i<=50;i++){
            if(pi-i*b>=0)
            ans=max(ans,4+i*3+2*int((pi-i*b)/a));
            else break;
        }
        printf("%d\n",ans);
    }
}

总结:

这场比赛开了四题,过了一题。很失败的一场了。

开始比赛的时候看到有人过E题,于是也快速读题,五分钟成功签到。

然后根据过题的人数,我们开了D题和K题。D题卡在了对a1的枚举上,这其中有想到过位运算,但是忽略了对下一位的影响,没有找出规律,浪费了很多时间。

K题在最初只考虑了走直线的情况,后来反应过来走对角线,又卡在了精度上。其实题目中的精度只到了0.1,对所有情况进行一次枚举就可以,比赛时没有注意到这一点,很可惜。

A题在比赛开始的时候看了题面,没有理解,于是跳过了。在比赛最后的一个半小时看到过题的人数越来越多,心说还是再挣扎一下,于是开了题。其实逻辑还是比较简单,以后要增强英语阅读的能力了0v0。卡在了x可能为0上,以及最后的取模运算也有点小问题。结束比赛之后很快就过了,遗憾。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值