Codeforces Round #689 题解and补题

标签:数据   后缀   前缀   random   查找   map   回文   因此   return   

比赛链接:https://codeforces.ml/contest/1461

A. String Generation

给定字符长度和最大回文子串长度,输出一个由‘a‘,‘b‘,‘c‘构成的字符串。

解题代码:

#include <iostream>
using namespace std;
int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	int t;
	cin >> t;
	while(t--){
		int n,k;
		cin >> n >> k;
		int cnt = 0;
		for(int i = 0;i<n;i++){
			cout << char(‘a‘+cnt%3);
			cnt++;
		}
		cout << endl;
	} 
	return 0;
} 

B. Find the Spruce

给定一个矩阵,由‘*‘和‘.‘构成,数一下其中有多少个下面的结构。每个枚举会超时,解题思路是每次遍历矩阵,将不被三环绕的点删除。
技术图片

解题代码:

#include <iostream>
#include <cstring>
using namespace std;
const int maxn = 520;
char a[maxn][maxn];
int td = 0;
int count(int n,int m){
	int tres = 0;
	int b[maxn][maxn] = {0};
	//memset(b,0,sizeof(b));
	for(int i = 1;i<=n;i++){
		for(int j = 1;j<=m;j++){
			if(a[i][j] == ‘*‘){
				tres++;
				if(a[i-1][j]==‘*‘&&a[i][j-1]==‘*‘&&a[i][j+1]==‘*‘){
					b[i][j] = 1;
				}
			}
		}
	}
	for(int i = 1;i<=n;i++){
		for(int j = 1;j<=m;j++){
			if(a[i][j] == ‘*‘){
				if(b[i][j]!=1){
					a[i][j] = ‘.‘;
					td -= 1;
				}
			}
		}
	}
	return tres;
}
int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	int t;
	cin >> t;
	while(t--){
		int n,m;
		cin >> n >> m;
		memset(a,0,sizeof(a));
		int res = 0;
		for(int i = 1;i<=n;i++){
			for(int j = 1;j<=m;j++){
				cin >> a[i][j];
				if(a[i][j]==‘*‘)td+=1;
			}
		}
		while(td!=0){
			res += count(n,m);
		}
		cout << res << endl;
	} 
	return 0;
} 

C. Random Events(补题)

一个长度为n的数组,对其进行m次操作,每次有p的概率使前r个有序,问其最终有序的概率是多少

分析:如果后缀无序,前缀有序,无用,所以要从后缀开始处理,反推每一个有影响的实验都不发生,最后用1减去不满足的概率即满足的概率

补题代码:

#include <iostream>
using namespace std;
const int maxn = 1e5 + 5;
int a[maxn];
int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	int t;
	cin >> t;
	while(t--){
		int n,m,k = 0;
		cin >> n >> m;
		for(int i = 1;i<=n;i++){
			cin >> a[i];
		}
		for(int i = n;i>1;i--){
			if(a[i]!=i){
				k = i;//找到最小有效变动的位置
				break;
			}
		}
		double res = 1;
		while(m--){
			int r;
			double p;
			cin >> r >> p;
			if(r<k) continue;
			else res *= (1-p);  //每次有效操作都不进行的概率
		}
		if(k==0) res = 0;//如果本身有序,就不用进行操作了
		printf("%.6f\n",1.0-res);
	}
}
  

D. Divide and Summarize(补题)

对于一个数列,可以进行操作以数列中最大值和最小值和的一般作为分界线,划分为左半部分和右半部分,询问是否可以使其中一个序列的元素和为s。

错误原因分析:思路错误,并非在需要查找时在进行查找操作,而是需要使用map记录可以找到的所有数值,查找时判断是否可以找到即可,c++中封装了而非查找的程序,因此在本题中并不需要手写二分查找,占用时间,题目给出的测试数据较大需要使用long long进行存储。

补题代码:

#include <iostream>
#include <map>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 5;
int a[maxn];
ll sum[maxn];
map<ll,int> mp;
void solve(int l,int r){
	//此处mid记录的是 mina和maxa 的中值的位置
	//位运算的优先级比加减运算更低,所以a[l]+a[r]>>1等价于(a[l]+a[r])/2 
	//upper_bound()返回的是一个地址,通过减去a的地址可以计算得到中间位置 
	int mid = upper_bound(a+1,a+r+1,a[l]+a[r]>>1)-a;
	//递归记录每一个可能出现的值 
	if(a[l]!=a[r])solve(l,mid-1), solve(mid,r);
	//将每一个出现的值在mp中记录,便于查找 
	mp[sum[r]-sum[l-1]] = 1;
} 
int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	int t;
	cin >> t;
	int n,m;
	while(t--){
		mp.clear();
		cin >> n >> m;
		for(int i = 1;i<=n;i++)cin >> a[i];
		sort(a+1,a+n+1);
		sum[0] = 0;
		for(int i = 1;i<=n;i++)sum[i] = sum[i-1]+a[i];
		solve(1,n);
		while(m--){
			int s;
			cin >> s;
			if(mp[s])cout << "Yes\n";
			else cout << "No\n";
		}
	}
}
  

Codeforces Round #689 题解and补题

标签:数据   后缀   前缀   random   查找   map   回文   因此   return   

原文地址:https://www.cnblogs.com/simulatedsakura/p/14123808.html

版权声明:完美者 发表于 2020-12-17 12:37:52。
转载请注明:Codeforces Round #689 题解and补题 | 完美导航

暂无评论

暂无评论...