牛客周赛 Round 51 (ABCDEF)

牛客周赛 Round 51比赛链接

A.小红的同余

题意

给一个奇数m,请你找出一个数 x x x ( 0 ≤ x < m 0 \le x < m 0x<m) 使得 2 x ≡ 1 ( m o d   m ) 2x \equiv 1 (mod\ m) 2x1(mod m)

思路

2 x ≡ 1 ( m o d   m ) 2x \equiv 1(mod \ m) 2x1(mod m) 2 x 2x 2x 取余m等于1. 那么由于m是奇数, 很容易想到一个方案 2 x = m + 1 2x = m+1 2x=m+1 , 即 x = m + 1 2 x = \frac{m+1}{2} x=2m+1

代码

#include<bits/stdc++.h>
using namespace std;
#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define int long long
#define rep(i,l,r) for(int i = l;i<=r;i++)
#define per(i,r,l) for(int i = r;i>=l;i--)
const int INF = 0x3f3f3f3f3f3f3f3f;
typedef pair<int,int> PII;
void solve(){
	int m;
	cin>>m;
	cout<<(m+1)/2;	
}
signed main(){
	int T = 1;
	// cin>>T;
	while(T--){
		solve();
	}
	return 0;
}

B.小红的三倍数

题意

给n个数,问是否存在一种方案,使得 这n个数拼接之后是3的倍数

思路

这里要用到一个数学知识,即x是3的倍数等价于 x的每一位相加的结果是3的倍数

123 ,按位相加后$1+2+3 = 6 ,6 % 3 == 0 $ 于是123是3的倍数。

所以我们不需要关心拼接的方案,只需要将每个数按位加和。 判断最终的总和是不是3的倍数即可。

代码

#include<bits/stdc++.h>
using namespace std;
#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define int long long
#define rep(i,l,r) for(int i = l;i<=r;i++)
#define per(i,r,l) for(int i = r;i>=l;i--)
const int INF = 0x3f3f3f3f3f3f3f3f;
typedef pair<int,int> PII;
void solve(){
	int n;
	cin>>n;
	int ans =0;
	rep(i,1,n){
		string str;
		cin>>str;
		for(auto p : str){
			ans += (p - '0');
		}
	}
	if(ans%3 == 0) cout<<"YES\n";
	else cout<<"NO\n";
}
signed main(){
	int T = 1;
	// cin>>T;
	while(T--){
		solve();
	}
	return 0;
}

C.小红充电

题意

题目中的题意就很好懂,我这边直接粘贴下来

思路

如果当前的电量x小于超级充电的门槛电量t。 那么我们直接开启超级快充直到充满即可

a n s = 100 − x c ( x ≤ t ) ans = \frac{100-x}{c}(x \le t) ans=c100x(xt)

如果当前的电量x大于超级充电的门槛电量t。 那么我们有两个选择

  1. 使用普通充电,耗时 t 1 = 100 − x b t1 = \frac{100-x}{b} t1=b100x
  2. 先玩游戏使得电量等于门槛电量t,然后开始超级快充 ,耗时 t 2 = x − t y + 100 − t c t2 = \frac{x-t}{y} + \frac{100-t}{c} t2=yxt+c100t

最终答案为 a n s = m i n ( t 1 , t 2 ) ans = min(t1,t2) ans=min(t1,t2)

代码

#include<bits/stdc++.h>
using namespace std;
#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define int long long
#define rep(i,l,r) for(int i = l;i<=r;i++)
#define per(i,r,l) for(int i = r;i>=l;i--)
const int INF = 0x3f3f3f3f3f3f3f3f;
typedef pair<int,int> PII;
void solve(){
	int x,y,t,a,b,c;
	cin>>x>>y>>t>>a>>b>>c;
	if(x <= t) {printf("%.8lf",(100 - x+0.0)/c);}
	else{
		double ans1 = 0;
		double ans2 = 0;
		ans1 = (100.0-x)/b;
		ans2 = (x-t+0.0)/y + (100.0-t)/c;
		printf("%.8lf",min(ans1,ans2));
	}
	return ;
}
signed main(){
	int T = 1;
	// cin>>T;
	while(T--){
		solve();
	}
	return 0;
}

D. 小红的 gcd

题意

g c d ( a , b ) gcd(a,b) gcd(a,b) , 其中 1 ≤ a ≤ 1 0 1 0 6 , 1 ≤ b ≤ 1 0 9 1\le a \le 10^{10^6}, 1\le b \le 10^9 1a10106,1b109

思路

本题考察辗转相除法。 即 g c d ( a , b ) = g c d ( b , a % b ) gcd(a,b) = gcd(b,a\%b) gcd(a,b)=gcd(b,a%b)因此我们计算出 c = a % b c = a\%b c=a%b 之后, 再使用基本的 g c d gcd gcd就可以得出结果于是我们问题就变为了如何求 a % b a\%b a%b

我们设a一共有n位,每一位为 a 1 , a 2 , . . . , a n a_1,a_2,...,a_n a1,a2,...,an 。那么有 a = ( ( ( 0 + a 1 ) ∗ 10 + a 2 ) ∗ 10... ) + a n a = (((0+a_1)*10+a_2)*10...)+a_n a=(((0+a1)10+a2)10...)+an

于是 a % b = ( ( ( ( 0 + a 1 ) ∗ 10 % b + a 2 ) ∗ 10 % b . . . ) + a n ) % b a\%b = ((((0+a_1)*10\%b+a_2)*10\%b...)+a_n)\%b a%b=((((0+a1)10%b+a2)10%b...)+an)%b .这样就可以保证运算过程中的数据始终在 l o n g   l o n g long\ long long long的范围内

代码

#include<bits/stdc++.h>
using namespace std;
#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define int long long
#define rep(i,l,r) for(int i = l;i<=r;i++)
#define per(i,r,l) for(int i = r;i>=l;i--)
const int INF = 0x3f3f3f3f3f3f3f3f;
typedef pair<int,int> PII;
void solve(){
	string a;
	int b;
	cin>>a>>b;
	int aa = 0;
	for(auto p : a){
		aa = aa*10 + p - '0';
		aa %= b;
	}
	cout<<__gcd(aa,b)<<endl;
}
signed main(){
	int T = 1;
	// cin>>T;
	while(T--){
		solve();
	}
	return 0;
}

E.小红走矩阵

题意

有一个 n ∗ n n*n nn 的矩阵,小红从 ( 1 , 1 ) (1,1) (1,1) 走到 ( n , n ) (n,n) (n,n) ,定义一条路径的权值为经过的所有点的最大值 . 请你找到权值最小的路径

思路

求某个东西的 最小的最大值 .考虑二分答案 .

我们假设要找一条权值不大于 k k k的路径 , 那么显然 , 所有大于 k k k的点我们都不能走 , 所以在本次check中 , 将所有大于k的点都视为障碍物,使用bfs检查是否能从起点走到重点 , 若能则代表 a n s ≤ k ans \le k ansk , 否则 a n s > k ans > k ans>k

代码

#include<bits/stdc++.h>
using namespace std;
#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define int long long
#define rep(i,l,r) for(int i = l;i<=r;i++)
#define per(i,r,l) for(int i = r;i>=l;i--)
const int INF = 0x3f3f3f3f3f3f3f3f;
typedef pair<int,int> PII;
int n;
bool vis[505][505];
int nextx[4] = {0,0,1,-1};
int nexty[4] = {1,-1,0,0};
int mp[505][505];
bool check(int mid){
	if(mp[1][1] > mid) return false;
	memset(vis,0,sizeof(vis));
	queue<PII> q;
	q.push({1,1});
	vis[1][1] = true;
	while(q.size()){
		int x = q.front().first;
		int y = q.front().second;
		q.pop();
		if(x == n && y == n) return true;
		for(int i = 0;i<4;i++){
			int nx = x + nextx[i];
			int ny = y + nexty[i];
			if(nx < 1 || nx > n || ny < 1 || ny > n || vis[nx][ny]) continue;
			if(mp[nx][ny] > mid) continue;
			vis[nx][ny] = true;
			q.push({nx,ny});
		}
	}
	return false;
}
void solve(){
	cin >> n;
	for(int i =1;i<=n;i++){
		for(int j = 1;j<=n;j++) cin>>mp[i][j];
	}
	int l = 1,r = 1e9+5;
	while(l<r){
		int mid = (l+r) >> 1;
		if(check(mid)){
			r = mid;
		}else
		l = mid+1;
	}
	cout<<l;

}
signed main(){
	int T = 1;
	// cin>>T;
	while(T--){
		solve();
	}
	return 0;
}	

F.小红的数组

题意

给n个数 a 1 , a 2 , . . . , a n a_1,a_2,...,a_n a1,a2,...,an , 以及q组询问 , 每次询问两个参数 l , r l,r l,r , 问区间连续子段和的绝对值最大是多少 . 即有 l ≤ x ≤ y ≤ r l \le x \le y \le r lxyr , 求最大的 a b s ( a [ x ] + a [ x + 1 ] + . . . + a [ y ] ) abs(a[x] + a[x+1] +... + a[y]) abs(a[x]+a[x+1]+...+a[y]) 是多少

思路

先对a数组进行求前缀和, s [ i ] = ∑ j = 1 i a [ j ] s[i] = \sum _{j=1}^i a[j] s[i]=j=1ia[j]

于是求 a b s ( a [ x ] + a [ x + 1 ] + . . . + a [ y ] ) abs(a[x]+a[x+1]+...+a[y]) abs(a[x]+a[x+1]+...+a[y]) 就等价于求 a b s ( s [ y ] − s [ x − 1 ] ) abs(s[y] - s[x-1]) abs(s[y]s[x1]) , 而题目规定 l ≤ x ≤ y ≤ r l \le x \le y \le r lxyr , 那么我们只需要找到 M A X i = l − 1 r s [ i ] MAX_{i=l-1}^r s[i] MAXi=l1rs[i] , 以及 M I N i = l − 1 r s [ i ] MIN_{i=l-1}^r s[i] MINi=l1rs[i] , 二者进行相减即可得出答案。

对于求区间最大/最小值问题, 我们使用ST表即可。

注意使用cin和cout可能会超时,需要关闭IO同流。

代码

#include<bits/stdc++.h>
using namespace std;
#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define int long long
#define rep(i,l,r) for(int i = l;i<=r;i++)
#define per(i,r,l) for(int i = r;i>=l;i--)
const int INF = 0x3f3f3f3f3f3f3f3f;
typedef pair<int,int> PII;
int lg[500005];
int n;	
int a[500005];
int f1[500005][30];
int f2[500005][30];
void init(){
	lg[1] = 0;
	rep(i,2,500003) lg[i] = lg[i>>1]+1;
	rep(i,1,n) {
		f1[i][0] = a[i];
		f2[i][0] = a[i];
	}
	for(int j = 1;j<=lg[n+1];j++){
		for(int i = 0;i <= n-(1<<j)+1;i++){
			f1[i][j] = max(f1[i][j-1],f1[i+(1<<(j-1))][j-1]);
			f2[i][j] = min(f2[i][j-1],f2[i+(1<<(j-1))][j-1]);
		}
	}
}
void solve(){
	cin>>n;
	for(int i = 1;i<=n;i++){
		cin>>a[i];
		a[i] += a[i-1];
	}
	init();
	int q;
	cin>>q;
	while(q--){
		int l, r;
		cin>>l>>r;
		l--;
		int log = lg[r-l+1];
		int ans = \
		max(f1[l][log],f1[r-(1<<log)+1][log])- \
		min(f2[l][log],f2[r-(1<<log)+1][log]);
		cout<<ans<<'\n';
	}
}
signed main(){
	IO;
	int T = 1;
	// cin>>T;
	while(T--){
		solve();
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值