牛客第八场 题解

比赛传送门
作者: fn


签到题

E题 Rise of Shadows 阴影的升起

题目大意
判断 a a a 是否既是闰年又是质数

分析
闰年不可能是质数

#include<bits/stdc++.h>
#define ll long long
using namespace std;

int main(){ 
	ios::sync_with_stdio(0); cin.tie(0);
	int t; cin>>t;
	while(t--){
		cout<<"no"<<endl;
	}
	return 0;
}

基本题

A题 Ares, Toilet Ares 阿瑞斯,厕所阿瑞斯

题目大意
已知一支队伍能过 a a a 道题,有一定概率能过下一题。输出过题数的期望(对4933取模)。

考察内容
乘法逆元

注意

  1. x = 0 x=0 x=0 时不计入失败概率
  2. 及时取模
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int MOD = 4933;
ll n,m,k,a=1,l,b=1,c,flag=0;

ll x, y;
void exgcd(ll a, ll b)
{
    if(b == 0)
    {
        x = 1;
        y = 0;
        return;
    }
    exgcd(b, a % b);
    ll Last_x = x;
    x = y;
    y = Last_x - a / b * y;
}

int main()
{
	cin>>n>>m>>k>>c>>l;
    for(int i=1;i<=k;i++){
    	ll x,y,z;
    	cin>>x>>y>>z;
    	if(x==0) continue; // 特判 
    	flag=1;
    	y=z-y;
    	a=a*y%MOD; // 注意取模 
    	b=b*z%MOD;
	}
	exgcd(b, MOD);
    x = (x % MOD + MOD) % MOD;
    printf("%lld", (c+a * (long long)(x) )% MOD);
    return 0;
}

K题 Yet Another Problem About Pi 关于圆周率的另一个问题

题目大意
在间距为 w w w , d d d 的网格上走 π π π 的距离,求最多经过几个网格区域。

考察内容
贪心,枚举,数学知识

分析
贪心,只走直线短边或对角线。直线短边每走一段,新经过区域为 2。对角线每走一段,新经过区域为 3 。
设一共走了 x x x 条直线, y y y 条对角线,直线短边长 m i n 1 = m i n ( w , d ) min1=min(w,d) min1=min(w,d) ,对角线长 d 1 = w 2 + d 2 d1=\sqrt{w^2+d^2} d1=w2+d2 ,经过网格区域数 f ( x , y ) f(x,y) f(x,y) ,则有

{ x ∗ m i n 1 + y ∗ d 1 ≤ π f ( x , y ) = 2 x + 4 + 3 y \left\{ \begin{aligned} x*min1+y*d1≤π \\ f(x,y)=2x+4+3y \end{aligned} \right. {xmin1+yd1πf(x,y)=2x+4+3y

求解 m a x ( f ( x , y ) ) max(f(x,y)) max(f(x,y))
f ( x , y ) f(x,y) f(x,y) 代入 y = π − x ∗ m i n 1 d 1 y=\frac{π-x*min1}{d1} y=d1πxmin1 后变为 f ( x ) f(x) f(x) ,求导,发现导数 f ′ ( x ) = 2 − 3 m i n 1 d 1 f'(x) = 2-3\frac{min1}{d1} f(x)=23d1min1 ,为常数,只能在 x = 0 x=0 x=0 x x x 最大的合法取值处取到 f ( x ) f(x) f(x) 最大值。

考虑到 x , y x,y x,y 为非负整数,不妨在两端枚举 x , y x,y x,y 的取值,取合法的最大值。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e6+10;
ll n,m,a[N];

double pi=3.141592653589793238462643383;
double min1,d1; 
 
ll f(ll x){
	ll y=(pi-x*min1)/d1;
	return 2*x+4+3*y;
} 

bool ck(ll x,ll y){
	if(x*min1+y*d1<=pi)return 1; //
	else return 0;
}

int main(){
	ios::sync_with_stdio(0); cin.tie(0);
  int t; cin>>t;
  while(t--){
	ll ans=0;
	double w,d; 
	cin>>w>>d;
	min1=min(w,d);
	d1=sqrt(w*w+d*d);
	
	ll x=(pi+min1+0.0000000001)/min1;
	
	ll num=2000; //
	for(int i=0;i<=min(num,x);i++){ // 0到num
		if(ck(i,(ll)(pi-x*min1)/d1))
		{
			ans=max(ans,f(i));
		}
	}
	
	for(int i=max((ll)0,x-num);i<=x;i++){ // x-num 到 x 
		if(ck(i,(ll)(pi-x*min1)/d1))
		{
			ans=max(ans,f(i));
		}
	}

	x=(pi+min1+0.0000000001)/min1; // 全直
	ans=max(ans,2*x+2);
	 
	x=(pi+d1+0.0000000001)/d1; // 全斜 
	ans=max(ans,3*x+1);

	cout<<ans<<endl;
  }
  return 0;
}
/*
3
0.91 0.91
0.01 0.01
0.0001 0.0001


11
670
66647
*/ 

进阶题

D题 OR 或运算

题目大意
给出相邻两位 𝑎 𝑖 − 1 or ⁡ 𝑎 𝑖 𝑎_{𝑖−1} \operatorname{or} 𝑎_𝑖 ai1orai 𝑎 𝑖 − 1 + 𝑎 𝑖 𝑎_{𝑖−1} + 𝑎_𝑖 ai1+ai 的结果,询问有多少个 a i a_i ai 序列满足要求

考察内容
位运算

分析
因为 𝑎 𝑖 − 1 + 𝑎 𝑖 = 𝑎 𝑖 − 1 or ⁡ 𝑎 𝑖 + 𝑎 𝑖 − 1 and ⁡ 𝑎 𝑖 𝑎_{𝑖−1}+𝑎_𝑖=𝑎_{𝑖−1} \operatorname{or} 𝑎_𝑖 + 𝑎_{𝑖−1} \operatorname{and} 𝑎_𝑖 ai1+ai=ai1orai+ai1andai ,可以求出相邻两位按位与的结果。
又因为 a [ 1 ] a[1] a[1] 确定就能确定整个序列,所以只需枚举 a [ 1 ] a[1] a[1] 的每个二进制位。

对于 a [ 1 ] a[1] a[1] 的每个二进制位,扫一遍按位或和按位与数组的相应位置,来判断01能不能放。

  • 如果01都可以放,结果就*2
  • 如果01只能放一个,结果不变
  • 如果01都不能放,结果变成0

复杂度 31 ∗ O ( n ) 31*O(n) 31O(n) ,其中 31 是 a [ 1 ] a[1] a[1] 的位数

#include<bits/stdc++.h>
#define ll long long
using namespace std;

const int MN = 100005;

int N, B[MN], C[MN];

void Solve() {
	scanf("%d", &N);
	for (int i = 1; i <= N - 1; ++i) scanf("%d", &B[i]); // or(按位或)后的值
	for (int i = 1; i <= N - 1; ++i) scanf("%d", &C[i]), C[i] -= B[i]; // 记录C[i]-B[i]即 and(按位与)后的值 
	
	int ans = 1;
	for (int j = 0; j < 31; ++j) { // 枚举a[1]的每一位 
		int a0 = 1, a1 = 1;
		for (int i = 1; i <= N - 1; ++i) {
			int vo = B[i] >> j & 1; // 取出B[i]第j位 
			int va = C[i] >> j & 1; // 取出C[i]第j位
			int b0 = 0, b1 = 0;
			if (vo && va)
				b1 = a1; // 都是1,只有1能保留 
			if (vo && !va)
				b1 = a0, b0 = a1; // 01都有,都能保留 
			if (!vo && !va)
				b0 = a0; // 都是0,只有0能保留 
			a0 = b0, a1 = b1; //
		}
		ans *= a0 + a1; // 更新答案 
	}
	
	printf("%d\n", ans);
}

int main() { // AC代码 
	Solve();
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值