【牛客训练记录】北京信息科技大学第十六届程序设计竞赛

训练情况

赛后反思

K题是简单DP,没看出来

A题

分类讨论找不同

#include <bits/stdc++.h>
#define int long long

using namespace std;

void solve(){
	int a,b,c; cin>>a>>b>>c;
	if(a==b) cout<<c<<endl;
	else if(b == c) cout<<a<<endl;
	else cout<<b<<endl;	
}

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

E题

我们每次可以选择区间 \([1,i]\) 进行翻转,要使得序列最后有序,首先我们必须将有序的部分放到后面,因为区间 \([1,i]\) 操作会使前面的部分翻转,导致原有的有序性被破坏,所以我们考虑先把序列翻转成 \([n,n-1,n-2,\cdots,3,2,1]\) 这种,所以我们直接循环 \(1 \sim n\) 找对应数的下标,将其先翻转到第一个,然后再翻转区间 \([1,n-i+1]\) 把这个数字放在后面的有序部分,这样子接下来的操作不会影响到后面的有序部分,最后再进行一次区间 \([1,n]\) 翻转即可。

#include <bits/stdc++.h>
#define int long long

using namespace std;

void solve(){
	int n; cin>>n;
	int tot = n;
	vector<int> a(n + 1);
	for(int i = 1;i<=n;i++) cin>>a[i];
	vector<int> ans;
	for(int i = 1;i<=n;i++){
		for(int j = 1;j<=n-i+1;j++){
			if(a[j] == i){
				if(j == n-i+1) continue;
				ans.push_back(j);
				reverse(a.begin() + 1,a.begin() + 1 + j);
				ans.push_back(n-i+1);
				reverse(a.begin() + 1,a.begin() + 1 + n - i + 1);
			}
		}
	}
	ans.push_back(n);
	cout<<ans.size()<<endl;
	for(auto i:ans) cout<<i<<" ";
	cout<<endl;
}

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

G题

这题我们容易想到贪心的思维,因为因为长度为 \(n\) 的数组进行 MEX 元素最大的值域只能到 \(n\),所以对于较大的元素我们是不需要 MEX 的,首先我们对数组进行排序,再求一个后缀和,枚举 MEX 的值,对于小于边界的部分进行 MEX,大于边界的部分直接求和,所以最后的答案就是 \(i^2+\sum_{j=i}^{n}a_j\) 取大值即可。

#include <bits/stdc++.h>
#define int long long

using namespace std;

void solve(){
	int n; cin>>n;
	vector<int> a(n + 1);
	for(int i = 1;i<=n;i++) cin>>a[i];
	sort(a.begin() + 1,a.end());
	vector<int> suf(n + 3);
	suf[n] = a[n];
	for(int i = n-1;i;i--) suf[i] = suf[i+1] + a[i];
	int ans = 0;
	for(int i = 0;i<=n;i++){
		ans = max(ans,i*i+suf[i+1]);
		// cout<<i*i<<" "<<suf[i+1]<<endl;
	}
	cout<<ans<<endl;
}

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

H题

这题我们单独考虑进位对答案的贡献,对于一个数 \(x\),首先肯定需要 \(x\) 秒,接下来就是考虑进位的情况了,最低位对答案的多余贡献为 \(\lfloor \frac{x}{10} \rfloor\) ,比如 \(12345\) 这个数显然最低位会进位 \(1234\) 次,其次的低位会进位 \(123\) 次,依次类推,所以 \(12345\) 的答案就是 \(12345 + 1234 + 123 + 12 + 1\),我们使用 while 循环对答案进行累加即可。

#include <bits/stdc++.h>
#define int long long

using namespace std;

void solve(){
	int x; cin>>x;
	int ans = x;
	while(x){
		x/=10;
		ans+=x;
	}	
	cout<<ans<<endl;
}

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

I题

我们直接模拟,开一个变量记录当前位置,往某一边先往某一边再改方向即可。

#include <bits/stdc++.h>
#define int long long

using namespace std;

void solve(){
	int n,k; cin>>n>>k;
	char s[n+1];
	getchar();
	for(int i = 1;i<=n;i++) cin>>s[i];
	int pos = k;
	int ans = 0;
	while(pos>=1&&pos<=n){
		if(s[pos] == '<'){
			s[pos] = '>';
			pos--;
		} else if(s[pos] == '>'){
			s[pos] = '<';
			pos++;
		}
		ans++;
	}
	cout<<ans<<endl;
}

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

J题

这题每一个段的长度都是最后一个数字,这题我们考虑倒着想,最后一段的长度就是最后一个元素,那我们就可以从后面往前推导每一段了,所以我们从最后面开始往前看看是否能划分即可。

#include <bits/stdc++.h>
#define int long long

using namespace std;

void solve(){
	int n; cin>>n;
	vector<int> a(n + 1);
	for(int i = 1;i<=n;i++) cin>>a[i];
	int pos = n;
	int ans = 0;
	while(pos>0){
		pos -= a[pos];
		ans++;
	}	
	if(pos==0) cout<<ans<<endl;
	else cout<<-1<<endl;
}

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

K题

段首和段尾都可以代表段长度,这题需要用到DP(动态规划)的算法,dp[i] 代表 1 ~ i 的最大段数,首先我们对 dp 数组进行全部初始化成无穷大,对于每一个位置 i,只要 i - a[i] 和 i + a[i] - 1 没有超出边界,对于每一个位置 i 可以从 i 位置往左 a[i] 个位置 往右 a[i] 个位置转移而来,所以动态规划状态转移方程为 dp[i]=min(dp[i],dp[i-a[i]]+1) / dp[i+a[i]-1]=min(dp[i+a[i]-1],dp[i-1]+1) ,最后我们判断 dp[n] 即(1~n)是否被更新过,如果是无穷大就是无解输出 -1,否则就是有解,直接输出 dp[n] 的值即可。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pb push_back
#define se second
#define fi first
//#define int long long
const int inf = 1e9 + 10;

void solve(){
	
	int n;cin >> n;
	
	vector<int> a(n + 1);
	for(int i = 1 ; i <= n ; i++) cin >> a[i];
	
	vector<int> dp(n + 1 , inf);
	dp[0] = 0;
	for(int i = 1 ; i <= n ; i++){
		if(i + a[i] - 1 <= n ){
			dp[i + a[i] - 1] = min(dp[i + a[i] - 1] , dp[i - 1] + 1);
		}
		if(i - a[i] + 1 > 0){
			dp[i] = min(dp[i] , dp[i - a[i]] + 1);
		}
	}
	
	cout << (dp[n] == inf ? -1 : dp[n]) << '\n';
	
}
signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	
	int t = 1;
 	cin >> t;
	while(t--){
		solve();
	}
	return 0; 
} 

N题

分成两段,取每段下标最大的,所以我们 \(a_n\) 肯定会被选到,要保证答案最大,所以另一段我们就从下标 \(1 \sim n-1\) 中选最大的即可。

#include <bits/stdc++.h>
#define int long long

using namespace std;

void solve(){
	int n; cin>>n;
	vector<int> a(n + 1);
	for(int i = 1;i<=n;i++) cin>>a[i];
	int mi = a[1];
	for(int i = 2;i<n;i++) mi = min(mi,a[i]);
	cout<<mi+a[n]<<endl;	
}

signed main(){
	int T; cin>>T; while(T--)
	solve();
	return 0;
}
posted @ 2024-11-20 21:09  MNNUACM_2024ZY  阅读(99)  评论(0)    收藏  举报