3.31~4.6

牛客月赛113

A

签到

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

int main(void){
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	int sum = 1;
	string s;
	cin >> s;
	for(char i : s){
		if(i == '-') sum -= 1;
		else sum *= 2;
	}
	cout << (sum >= 2025 ? "YES\n" : "NO\n");
	return 0;
}

B

统计相邻相同字符即可

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

int main(void){
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	int n,times=0;
	string s;
	cin >> n >> s;
	for(int i=1;i<n;i++){
		if(s[i] == s[i-1])
			times++;
	}
	cout << (times<=1 ? "YES\n" : "NO\n");
	return 0;
}

C

很简单的题,就是对数组进行几个判定:

1.如果输入数组里出现了逆序的情况,NO

2.如果所有输入数组里有相同数的情况,NO

3.将所有数组合并,如果有逆序的情况,NO

否则,YES

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5+1;

vector <int> vec;

int main(void){
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	int q,pd=1,sum=0;
	cin >> q;
	while(q--){
		int k;
		cin >> k;
		sum += k;
		int arr[maxn];
		arr[0] = 0;
		for(int i=1;i<=k;i++){
			cin >> arr[i];
			if(arr[i] < arr[i-1])
				pd = 0;
			vec.push_back(arr[i]);
		}
	}
	sort(vec.begin(),vec.end());
	for(int i=1;i<sum;i++){
		if(vec[i]-vec[i-1] != 1){
			pd = 0;
			break;
		}
	}
	cout << (pd ? "YES\n" : "NO\n");
	return 0;
}

D

思维题,需要惊人的注意力才能注意到:

对数组升序排序后,在每个"断点"(a[i]-a[i-1]!=1)处进行处理,sum累加上a[i]-a[-1]-1,因为每个断点所隔开的区间里,区间里的数都是同时变为0的

有特判:输入数组为相同数,0;输入数组没有0,-1

#include <bits/stdc++.h>
#define int long long 
using namespace std;
const int maxn = 1e5+1;

int a[maxn];

signed main(void){
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	int n,pd=1;
	cin >> n;
	for(int i=0;i<n;i++){
		cin >> a[i];
		if(i && a[i]!=a[i-1])
			pd = 0;
	}
	sort(a,a+n);
	if(pd){
		cout << "0\n";
		return 0;
	}
	if(a[0]){
		cout << "-1\n";
		return 0;
	}
	int sum = 0;
	for(int i=1;i<n;i++){
		if(a[i]-a[i-1] != 1 && a[i]!=a[i-1]){
			sum += a[i]-a[i-1]-1;
		}
	}
	cout << ++sum << '\n';
	return 0;
}

E

区间DP+预处理

有难度的,揣摩了官方题解才过。简而言之就是通过预处理左右合法区间,然后dp每个大小区间,逐步推出最大的区间数k

预处理:

pre[]:左侧与ai不互质的最近的j

nex[]:右侧与ai不互质的最近的i

状态转移:

<font style="color:rgb(0, 0, 0);">dp[i] = max(dp[i], dp[j-1] + 1)</font>

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 2e3+5;

int n,a[N],pre[N],nex[N],dp[N];

void solve(){
	for(int i=1;i <= n;i++){
		for(int j=1;j < i;j++){
			if(__gcd(a[i],a[j]) != 1){
				pre[i] = max(pre[i] , j);
				nex[j] = min(nex[j] , i);
			}
		}
	}
	for(int i=1;i <= n;i++){
		int t = 1e9;
		for(int j=i;j >= 1;j--){
			if(nex[j] > i)
				t = min(t,pre[j]);
			else if(t >= j && dp[j-1] != -1)
				dp[i] = max(dp[i], dp[j-1]+1);
		}
	}
	cout << dp[n] << '\n';
}

signed main(void){
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	cin >> n;
	memset(dp,-1,sizeof(dp));
	dp[0] = 0;
	memset(nex,0x3f,sizeof(nex));
	for(int i=1;i <= n;i++)
		cin >> a[i];
	solve();
	return 0;
}

洛谷P1004

这道dp还是有难度的,洛谷题名绿绿的

容易想到dp和dfs。dfs剪枝可以过;如果dp两遍,每遍都贪心找局部最优,这样可能会陷入局部最优解从而出错。

因此比较无脑的正解是四维dp

同时考虑如何第一遍到点(i,j)以及第二遍到点(k,l),共四种情况:

  • 路径 1 从 (i-1, j) 来,路径 2 从 (k-1, l) 来,前一状态为 <font style="color:rgb(0, 0, 0);">dp[i-1][j][k-1][l]</font>
  • 路径 1 从 (i-1, j) 来,路径 2 从 (k, l-1) 来,前一状态为 <font style="color:rgb(0, 0, 0);">dp[i-1][j][k][l-1]</font>
  • 路径 1 从 (i, j-1) 来,路径 2 从 (k-1, l) 来,前一状态为 <font style="color:rgb(0, 0, 0);">dp[i][j-1][k-1][l]</font>
  • 路径 1 从 (i, j-1) 来,路径 2 从 (k, l-1) 来,前一状态为 <font style="color:rgb(0, 0, 0);">dp[i][j-1][k][l-1]</font>

取最大的,所以状态转移方程为:
dp[i][j][k][l] = max(

max(dp[i-1][j][k-1][l], dp[i-1][j][k][l-1]),

max(dp[i][j-1][k-1][l], dp[i][j-1][k][l-1])

) + room[i][j] + room[k][l];

注意,当两遍的点重复,即i==k,j==l时,这个点的数被重复算了,要减去一遍的它if(i==k && j==l) dp[i][j][k][l] -= room[i][j];

code:

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

int dp[10][10][10][10]={0},room[10][10]={0};

int main(void){
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	int n,x,y,i;
	cin >> n;
	while(114514){
		cin >> x >> y >> i;
		if(!x) break;
		room[x][y] = i;
	}
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			for(int k=1;k<=n;k++)
				for(int l=1;l<=n;l++){
					dp[i][j][k][l] = max(max(dp[i-1][j][k-1][l],dp[i-1][j][k][l-1]),max(dp[i][j-1][k-1][l],dp[i][j-1][k][l-1])) + room[i][j] + room[k][l];
					if(i==k && j==l) dp[i][j][k][l] -= room[i][j];
				}
	cout << dp[n][n][n][n] << '\n';
	return 0;
}

成理蓝桥试炼赛

D

map模拟即可

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxn = 1e6+1;

int a[maxn],score;

map <int,int> ma;

signed main(void){
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	int n,m;
	cin >> n >> m;
	for(int i=0;i<n;i++)
		cin >> a[i];
	for(int i=0;i<n;i++){
		cin >> score;
		ma[a[i]] = score;
	}
	int sum = 0;
	for(int i=0;i<m;i++){
		int inp;
		cin >> inp;
		sum += ma[inp];
	}
	cout << sum << '\n';
	return 0;
}

剩下的题下周补了,这周事情实在多......

posted @ 2025-06-14 12:26  HLAIA  阅读(7)  评论(0)    收藏  举报