2024牛客寒假算法基础集训营5 题解 ( A,C,G,H,I,L,M )

2024牛客寒假算法基础集训营5 题解 ( A,C,G,H,I,L,M )

A mutsumi的质数合数

题意

有一个由 n n n 个正整数组成的数组,她想知道数组中质数和合数共有几个。

思路

由质数和合数的定义可知,正整数范围内除 1 1 1 外,要么是质数要么是合数,本题直接统计不是 1 1 1 的正整数的个数即可

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
			
int main(){
			
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
			
	int n;
	cin >> n;
	int cnt = 0;
	for(int i = 0;i < n;i++){

		int a;
		cin >> a;

		if(a != 0 && a != 1)cnt++;

	}

	cout << cnt;
			
	return 0;
}

C anon的私货

题意

在一个正数数组中夹带一些 0,只要数组的除全 0 连续子数组外的每个连续子数组的平均数都大于等于 1,最多可以夹带多少个 0

思路

如果在两数之间插入 0 0 0 的话,插入的位置左右两侧的数都会受影响
所以数组的第一个元素和最后一个元素要重点考虑,在数组前插 0 0 0 ,只有第一个元素会受影响,最后一个元素同理。

除此之外,设数组第 i i i 个元素为 a i a_i ai,可以把本题看作从第 1 1 1 位开始,每次对第 i i i i + 1 i+1 i+1 位( $ 1 \le i \lt n$),同时自减 m i n ( a i − 1 , a i + 1 − 1 ) min(a_i-1,a_{i+1}-1) min(ai1,ai+11),然后整个数组一共减去的值就是答案。

特别注意第一位和最后一位是否有剩余

代码

/*******************************
| Author:  AlwaysBeShine
| Problem: anon的私货
| Contest: NowCoder
| URL:     https://ac.nowcoder.com/acm/contest/67745/C
| When:    2024-02-21 15:48:37
| 
| Memory:  524288 MB
| Time:    2000 ms
*******************************/
#include <bits/stdc++.h>
#include <limits.h>
using namespace std;
typedef long long ll;
			
int main(){
			
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
			
	int n;	
    cin >> n;
    std::vector<ll> a(n+3,LLONG_MAX);
    for(int i = 1; i <= n;i++){

    	cin >> a[i];

    }
    ll cnt = 0;
    for(int i = 0;i <= n;i++){

    	if(a[i] >= 2 && a[i+1] >= 2){
    		
    		if(a[i] >= a[i+1]){
    			cnt += a[i+1] - 1;
    			a[i] -= (a[i+1] - 1);
    			a[i+1] = 1;


    		}else{

    			cnt += a[i] - 1;
    			a[i+1] -= (a[i] - 1);
    			a[i] = 1;

    		}

    	}

    	// for(int i = 1; i <= n;i++){

    	// 	cout << a[i] << " \n"[i==n];

    	// }

    }

    if(a[1] >= 2)cnt += a[1] - 1;
    cout << cnt;
			
	return 0;
}

G sakiko的排列构造(easy)

题意

构造一个长度为 n n n 的排列 p p p ,使得每一个 p i + i   ( 1 ≤ i ≤ n ) p_i+i\ (1\leq i\leq n) pi+i (1in) 都是质数。

思路

通过打表可发现规律
设第 i i i 位应该放的值为 a i a_i ai,当前使用的质数为 z k z_k zk (第 k k k 个质数)
倒着构造,提前预处理出小于等于 1 0 3 10^3 103 以内的所有质数,用第一个大于等于 n n n 的质数从最后一位开始倒着构造。

因为要构造一个排列,所以数字不能重复,也不能大于 n n n
所以要求 z k − i z_k - i zki 必须没有出现过,并且 z k − i ≤ n z_k - i \le n zkin 如果满足条件,那么 a i = z k − i a_i = z_k - i ai=zki
否则 k k k 自减(就是再往小找最大的满足 z k − i z_k - i zki 没出现过的质数)再循环这个情况

如果构造过程中 k < 1 k \lt 1 k<1 (也就是质数不够用了),那么就构造不出来,否则就构造的出来

代码

/*******************************
| Author:  AlwaysBeShine
| Problem: sakiko的排列构造(easy)
| Contest: NowCoder
| URL:     https://ac.nowcoder.com/acm/contest/67745/G
| When:    2024-02-21 16:49:29
| 
| Memory:  524288 MB
| Time:    2000 ms
*******************************/
/*******************************
| Author:  AlwaysBeShine
| Problem: B3716 分解质因子 3
| Contest: Luogu
| URL:     https://www.luogu.com.cn/problem/B3716
| When:    2024-02-11 15:50:18
| 
| Memory:  600 MB
| Time:    2500 ms
*******************************/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

vector<bool> isNotPrime(10100);
vector<int> prime;


int main(){

    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    prime.push_back(2);
	for(int i = 2;i <= 10000;i++){

		if(isNotPrime[i] == false){

			prime.push_back(i);
			
		}
		for(int j = 1;prime[j] * i <= 10000;j++){
			int temp = prime[j] * i;
			isNotPrime[temp] = true;
			
			if(i % prime[j] == 0)break;

		}
	}

    int pos;
    int n;
    cin >> n;
    for(int i = 1;i <= prime.size();i++){

    	if(prime[i] > n){

    		pos = i;
    		break;
    	}

    }
    vector<int>ans(n+5);
    map<int,int>mp;
    for(int i = n;i >= 1;i--){ //倒着来

    	if(pos < 1){

    		cout << "-1";
    		return 0;
    	}

    	while(pos >= 1 && (prime[pos] - i > n || mp[prime[pos] - i] == 1)){

    		pos--;

    	}

    	if(mp[prime[pos] - i] == 0){ //如果没出现过这个数

    		if(prime[pos] - i <= n){ //必须要小于等于 n
    			ans[i] = prime[pos] - i;
    			mp[prime[pos] - i] = 1; 

    		}else{ //如果大于等于n了或者出现过了

    			while(pos >= 1 && (prime[pos] - i > n || mp[prime[pos] - i] == 1)){

    				pos--;

    			}

    			if(pos < 1){

    				cout << -1;

    			}else{

    				ans[i] = prime[pos] - i;
    				mp[prime[pos] - i] = 1;

    			}

    		}
    	}

    }

    for(int i = 1;i <= n;i++){

    	cout << ans[i] << " ";

    }

    return 0;
}

H sakiko的排列构造(hard)

题意

同 easy 版,只有数据范围扩大到了 1 0 6 10^6 106

思路

同 easy 版

代码

/*******************************
| Author:  AlwaysBeShine
| Problem: sakiko的排列构造(easy)
| Contest: NowCoder
| URL:     https://ac.nowcoder.com/acm/contest/67745/G
| When:    2024-02-21 16:49:29
| 
| Memory:  524288 MB
| Time:    2000 ms
*******************************/
/*******************************
| Author:  AlwaysBeShine
| Problem: B3716 分解质因子 3
| Contest: Luogu
| URL:     https://www.luogu.com.cn/problem/B3716
| When:    2024-02-11 15:50:18
| 
| Memory:  600 MB
| Time:    2500 ms
*******************************/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

vector<bool> isNotPrime(1000010);
vector<int> prime;


int main(){

    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    prime.push_back(2);
	for(int i = 2;i <= 1000010;i++){

		if(isNotPrime[i] == false){

			prime.push_back(i);
			
		}
		for(int j = 1;prime[j] * i <= 1000010;j++){
			int temp = prime[j] * i;
			isNotPrime[temp] = true;
			
			if(i % prime[j] == 0)break;

		}
	}

    int pos;
    int n;
    cin >> n;
    for(int i = 1;i <= prime.size();i++){

    	if(prime[i] > n){

    		pos = i;
    		break;
    	}

    }
    vector<int>ans(n+5);
    map<int,int>mp;
    for(int i = n;i >= 1;i--){ //倒着来

    	if(pos < 1){

    		cout << "-1";
    		return 0;
    	}

    	while(pos >= 1 && (prime[pos] - i > n || mp[prime[pos] - i] == 1)){

    		pos--;

    	}

    	if(mp[prime[pos] - i] == 0){ //如果没出现过这个数

    		if(prime[pos] - i <= n){ //必须要小于等于 n
    			ans[i] = prime[pos] - i;
    			mp[prime[pos] - i] = 1; 

    		}else{ //如果大于等于n了或者出现过了

    			while(pos >= 1 && (prime[pos] - i > n || mp[prime[pos] - i] == 1)){

    				pos--;

    			}

    			if(pos < 1){

    				cout << -1;

    			}else{

    				ans[i] = prime[pos] - i;
    				mp[prime[pos] - i] = 1;

    			}

    		}
    	}

    }

    for(int i = 1;i <= n;i++){

    	cout << ans[i] << " ";

    }

    return 0;
}

I rikki的最短路

题意

rikki 在找 anon ,她准备去找 tomorin 问一下 anon 在哪。 (以下tomorin简称 T T T ,anon简称 A A A
寻找过程:找到 A A A ,将 A A A 带回 T T T 的位置,可以简单的理解为先找到 A A A 再去找 T T T
我们把寻找过程简化为一条数轴, rikki 在数轴上的坐标为 0 , T T T 在数轴上的坐标为 t t t A A A 在数轴上的坐标为 a a a
初始时 rikki 只知道 T T T 的坐标,而不知道 A A A 的坐标,因此 rikki 会先前往 T T T 的坐标。
而当 rikki 到达 T T T 的坐标时,就可以知道 A A A 的坐标。
rikki 的视野为 k k k ,若rikki当前坐标为 u u u ,则她可以看到 [ u − k , u + k ] [u-k,u+k] [uk,u+k] 区间内的东西,即 rikki 可能可以在移动到 T T T 所在坐标的过程中直接看到 A A A ,去找到 A A A ,省略先去找 T T T 的过程。
rikki 想知道她将 A A A 带回 T T T 的坐标最少需要移动多少距离。

思路

分类讨论

  1. A A A T T T 同向时,如果 ∣ A ∣ ≤ ∣ T ∣ \lvert A \rvert \le \lvert T \rvert AT,那么在找 T T T 的过程中就找到了 A A A 直接带走,不需要多走,答案就是 ∣ T ∣ \lvert T \rvert T
  2. 当 A 和 T T T 同向时,如果 ∣ A ∣ > ∣ T ∣ \lvert A \rvert \gt \lvert T \rvert A>T,那就得比上面那种情况,多走 2 ∗ ( ∣ A ∣ − ∣ T ∣ ) 2 * (\lvert A \rvert - \lvert T \rvert) 2(∣AT∣)
  3. A A A T T T 反向时,如果 ∣ A ∣ ≤ ∣ k ∣ \lvert A \rvert \le \lvert k \rvert Ak,一开始就知道 A A A 在哪,所以可以先找 A A A ,再带到 T T T
  4. T = 0 T = 0 T=0 时,同上理。
  5. A A A T T T 反向时,如果 ∣ A ∣ > ∣ T ∣ \lvert A \rvert \gt \lvert T \rvert A>T ,得先去找 T T T 再去找 A A A ,再找 T T T

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
			
int main(){
			
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
			
	ll t,a,k;
	cin >> t >> a >> k;
    if((t > 0 && a > 0) || (t < 0 && a < 0)){ //同向
		ll la = abs(a),lt = abs(t);
		if(la <= lt){ //去t路上能看见a

			cout << lt;

		}else{ //看不见a

			cout << la + la - lt;

		}

	}else if(a == 0){ //带着a去找t

		cout << abs(t);

	}else if(t == 0){ //直接知道a在哪 把他带回来

		cout << 2 * abs(a);

	}else{ //反向

		if(abs(a) > k){

			cout << 3*abs(t) + 2*abs(a);

		}else{

			cout << 2*abs(a) + abs(t);

		}

	}
			
	return 0;
}

L anon的星星

题意

玩一个游戏,胜利一局会获得一颗星星,失败一局会失去一颗星星,没有平局。 只知道自己玩了 n n n 局游戏,共获得了 x x x 颗星星。
求胜利了几局,失败了几局?

思路

设胜利了 i i i 局,则输了 $ n - i$ 局,判断 1 ≤ i ≤ n 1 \le i \le n 1in 是否存在 i − ( n − i ) = x i - (n-i) = x i(ni)=x 即可

代码

#include <iostream>
using namespace std;

int main() {
    int n, x;
    cin >> n >> x;

    for (int i = 0; i <= n; ++i) {
        int j = n - i;
        if (i - j == x) {
            cout << i << " " << j << endl;
            return 0;
        }
    }
    
    cout << -1 << endl;
    return 0;
}

M mutsumi的排列连通

题意

有两个排列,放置在一个 2 × n 2 \times n 2×n 的矩形中,每次你可以选择一个数字 x x x ,将两个排列内的 x x x 所在的单元格删除。
删除尽可能少的数字,使得矩形至少被分成两个连通块(不一定是矩形),
请输出最小的删除次数。若无法通过删除使得矩形被分成至少两个连通块,则输出 -1。
连通块:块内任意两点(可以是同一点)都可以找到至少一条只由上下左右组成的路径相连。
长度为 n n n 的排列为: 1 − n 1-n 1n 中,每个数字恰好出现一次。

思路

很容易思考出,答案只有 − 1 , 1 , 2 -1,1,2 1,1,2 三种可能

n = 1 n = 1 n=1 时,无解

n = 2 n = 2 n=2 时,如果两排列完全相同,无解;如果两排列不同,操作一次即可

n ≥ 3 n \ge 3 n3 时,判断第 2 2 2 位到第 n − 1 n-1 n1 位之间,两排列是否存在两个相同的元素在两排列种各自的下标之差为 1 1 1

​ 如果存在,则操作一次即可,否则要操作两次。

代码

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

void solve(){

    map<int,int>a;

	map<int,int>b;		
	int n,temp;
	cin >> n;
	vector<int>A(n+1,0);
	vector<int>B(n+1,0);
	for(int i = 1;i <= n;i++){

		
		cin >> temp;
		a[temp] = i;
		A[i] = temp;
	}
	bool ck = false;
	for(int i = 1;i <= n;i++){

		cin >> temp;
		b[temp] = i;
		B[i] = temp;
		if(abs(i - a[temp]) == 1 || i == a[temp] && i != n && i != 1){

			ck = true;

		}

	}

	if(n == 1){

		cout << "-1\n";

	}else if(n == 2){

		if(A[1] == B[1] && A[2] == B[2])cout << "-1\n";
		else{

			cout << "1\n";

		}
	}else{

		if(ck){

			cout << "1\n";

		}else{

			cout << "2\n";

		}

	}

}

int main(){

    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    int T;
    cin >> T;
    while(T--){

       solve();

    }

    return 0;
}
  • 14
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值