8.21CF专场题解

题目链接

简单点评一下同学们现在的问题:
1 简单思维讨论类型的题目,准确率还不够,每个题目都要经过全方面的考虑再去设计算法程序 不然就会像A题一样 有同学能错七八次 才能写对

程序写完以后自己多测测样例数据,
自己造数据去测

2 算法类型的题目不知道如何思考,这个需要慢慢积累

3 学习要踏实,勤奋,初赛训练的时候不要用编译器做题。综合来看同学们现在需要大量的积累,更加精细化的分类讨论能力,全方位的思考问题的耐心。心中有模拟赛,自然都是模拟赛

A题题解
很明显的一个分类讨论题目
如果字符串中存在相邻且相等的字符位置,那么记录下来 为pos
先输出1–pos 然后输出插入的字符 注意要跟pos pos+1位置的字符不一样,然后输出pos+1~ 末尾的字符 这样子就构造好了

如果不存在这样子的位置,那更好办了,直接输出字符串在末尾补一个不一样的字符即可

#include<bits/stdc++.h>
using namespace std;
char A[1010];
int main(){
	int a;
	cin>>a;
	char b;
	int ib;
	int ok=0;
	for(int i=1;i<=a;i++){
		cin>>A+1;
		int len = strlen(A+1);
		for(int j=1;j<=len;j++){
			if(A[j-1]==A[j]){
				ib=j;
				if(A[j]!='a'){
					b='a';
					ok=1;
				}
				else{
					b='b';
					ok=1;
				}
			}
		}
		int g=0;
		if(ok==0){
			for(int j=1;j<=len;j++){
				cout<<A[j];
				if(j==len){
					if(A[j]=='a'){
						cout<<'b';
					}
					else{
						cout<<'a';
					}
				}
			}
		}
		else{
			for(int j=1;j<=len;j++){
				if(j==ib){
					cout<<b;
				}
				cout<<A[j];
			}
		}
		ok=0;
		cout<<endl;
	}
	return 0;
}

B题题解
首先题目意思要读懂
给定一个2*n的矩阵,里面由两种方块组成:堵塞方块和自由方块,自由方块有且只会形成一个联通块(这个条件很重要),求符合条件的自由方块个数(把这个自由方块变成堵塞方块后恰好能把一个联通块割成3个联通块)

本题只需要特判即可

#include<bits/stdc++.h>
using namespace std;
void sol(){
    int n;cin>>n;
    char a[3][n+10];
    for(int i=1;i<=2;i++){
        for(int j=1;j<=n;j++){
            cin>>a[i][j];
        }
    }
    int cnt=0;
    for(int i=1;i<=n-2;i++){
        if(a[1][i]=='x'&&a[1][i+1]=='.'&&a[1][i+2]=='x'&&a[2][i]=='.'&&a[2][i+1]=='.'&&a[2][i+2]=='.')cnt++;
        if(a[2][i]=='x'&&a[2][i+1]=='.'&&a[2][i+2]=='x'&&a[1][i]=='.'&&a[1][i+1]=='.'&&a[1][i+2]=='.')cnt++;
    }
    cout<<cnt<<endl;
}
int main(){
    int t;cin>>t;
    while(t--)sol();
    return 0;
}

C题题解
给定一个由’(‘,’)‘和’‘三种字符组成的字符串,’‘出现在所有的奇数位,现在需要我们在’_‘中填入’(‘或’)',使得每个括号一定能够配对(保证一定存在这样的字符串),使得字符串的分数最大(每个括号左右下标差的累加值)

看到括号,就想到栈的使用,这道题的解法多样
枚举原字符串,一共有三种字符,分别进行操作

#include <iostream>
#include <cstring>
#include <queue>
#include <map>
#include <set>
#include <algorithm>
#include <cmath>
#include <vector>
#include <stack>
using namespace std;
typedef long long LL;
typedef pair<char,LL> PII;//开long long,求求你了,记得开long long 
const LL N=2e5+10;
const LL INF=1e18;
const double small=1e-16;
//千万不要用puts()和gets(),求求你了 
char s[N];
 
void solve()
{
	LL n;
	cin>>n;
	stack<PII> q;
	for(int i=1;i<=n;i++)cin>>s[i];
	LL res=0;
	for(int i=1;i<=n;i++)
	{
		if(s[i]=='_')//碰到'_'
		{
			if(q.size()&&(q.top().first=='('))//如果栈顶为左括号,优先满足
			{
				
				res+=(i-q.top().second);//配对成功
				q.pop();
			}
			else//否则入栈等待右括号
			{
				q.push({'_',i});
			}
		}
		else if(s[i]=='(')//碰到'('
		{
			q.push({'(',i});//直接入栈,等右边的‘_’
		}
		else if(s[i]==')')//碰到')'
		{
		    //if(q.size())cout<<q.top().first<<endl;
			if(q.size()&&(q.top().first=='('||q.top().first=='_'))'('和‘_’都可以配对
			{
				
				res+=(i-q.top().second);//配对成功
				q.pop();
			}
		}
	}
	//cout<<q.size()<<endl;//这里看到栈到后面总是空的,不用再处理了
	cout<<res<<endl;
}
 
int main()
{
    
	int t=1;
	cin>>t;
	while(t--)
	{
		solve();
	}
	return 0;
}

D 题题解
因为硬币会下落,所以说一开始硬币处于Y轴-2及以下都是收集不到的

#include<bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
int n;
signed main(){
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	cin>>n;
	while(n--){
		int x,y;
		cin>>x>>y;
		if(y<-1)cout<<"NO"<<endl;
		else cout<<"YES"<<endl;
	}
	return 0;
}

E题
构造一个最短的字符串满足存在子串a以及子序列b

最坏情况是 a + b,然后,考虑 a 是一定要整段出现在答案中,所以只需要枚举从 b 的第几个字符开始匹配即可,如果有 tmp 个字符匹配,答案就是 a.size() + b.size() - tmp

注意 b 中所有字母都要按顺序出现在 a 里,所以,一旦 b 中有一个字符不能和 a 匹配,之后的所有字符都不能和 a 匹配了,直接break,就不能再往下计算了

#include <bits/stdc++.h>

using namespace std;

#define int long long
using i64 = long long;

typedef pair<int, int> PII;
typedef pair<int, char> PIC;
typedef pair<double, double> PDD;
typedef pair<int, PII> PIII;
typedef pair<int, pair<int, bool>> PIIB;

const int N = 1e5 + 10;
const int maxn = 1e6 + 10;
const int mod = 998244353;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;

void solve()
{
	string a, b;
    cin >> a >> b;
    int ans = a.size() + b.size();
    for (int k = 0; k < b.size(); k ++ )
    {
        int tmp = 0;
        int lst = -1;
        for (int i = k; i < b.size(); i ++ )
        {
            bool flag = false;
            for (int j = lst + 1; j < a.size(); j ++ )
            {
                if (b[i] == a[j])
                {
                    flag = true;
                    lst = j;
                    tmp ++ ;
                    break;
                }
            }
            if (!flag) break;
        }
        ans = min(ans, (i64)(a.size() + b.size() - tmp));
    }
    cout << ans << '\n';
}

signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);

	int t = 1;
	cin >> t;
	while (t--)
	{
		solve();
	}
}

F题题解
贪心的使两个电影的评分尽可能的高且相近

1.若第i个人对两个评分不一样,取高的评分即可。

2.反之则考虑:

(1) 若ai=bi=0,则选择哪个电影都一样,所以不考虑

(2)若ai=1,则第i个人把评分给当前分低的

(3)若ai=-1,则第i个人把评分给当前分高的

#include<bits/stdc++.h>
using namespace std;
const int N =2e5+10;
int a1,b1;
int t,n,res;
void solve()
{
	ios::sync_with_stdio(false);
	cin.tie(0); 
	cin>>t;
	while(t--)
	{
		cin>>n;
        a1=b1=0;
		vector<int> a(n+1),b(n+1);
		for(int i=1;i<=n;i++) cin>>a[i];
		for(int i=1;i<=n;i++)
		{
			cin>>b[i];
			if(b[i]>a[i]) b1+=b[i];
			if(b[i]<a[i]) a1+=a[i];
		}
		for(int i=1;i<=n;i++)
		{
			if(a[i]==b[i])
			{
				if(a[i]*(a1-b1)>0) b1+=b[i];
				else a1+=a[i];
			}
		}
		cout<<min(a1,b1)<<endl; 
	}
}
int main()
{
	solve();
	return 0;
}

G题题解
这算是最难的一个 ,本套题里面
难度分1900
可以发现最好的策略,一定是先利用锻造并融化后损失最小的来获取经验。这个贪心是可以证明的。那我们发现a的范围是1e6,那么如果C大于最大的ai,那我们可以选择一个最小损失的方案一直执行让他小于最大的ai,小于ai后,这个数据范围可以发现,我们可以利用dp来得到1e6范围的所有答案,那么这道题就完成了

#include<bits/stdc++.h>
typedef long long LL;
using namespace std;
const int N =1e6+10;
int n,m;
void solve()
{
	vector<int> a(N),b(N);
	vector<int> d(1e6+10,1e7),dp(1e6+10);
	cin>>n>>m;
	int s=0;
    for(int i=1;i<=n;i++)
	{
		cin>>a[i];
		s=max(s,a[i]);
	} 
	for(int i=1;i<=n;i++)
	{
		cin>>b[i];
		d[a[i]]=min(d[a[i]],a[i]-b[i]);
	}
	for(int i=1;i<=1e6;i++) d[i]=min(d[i],d[i-1]);
	for(int i=1;i<=1e6;i++)
		if(i-d[i]>=0) dp[i]=max(dp[i],dp[i-d[i]]+1);
	LL res=0;
	for(int i=1;i<=m;i++)
	{
		int c;
		cin>>c;
		if(c>s)
		{
			int r=(c-s)/d[s]+1;
			c-=r*d[s];
			res+=r;
		}
		res+=dp[c];
		
	}
	cout<<res*2<<endl;
}
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0); 
	solve();
	return 0;
} 

H题题解
我们考虑贪心,先把所有子树能给出的颜色的最小值记录下来,记为maxval。如果当前根结点的值比maxval大,那么取maxval(因为根节点无法影响叶子结点),否则的话,根节点和maxval取平均,通过子树把当前根的贡献增大。
难度分1500 中规中矩的题目

#include <bits/stdc++.h>

const int maxn = 3e5 + 10;
using namespace std;
int n, a[maxn], tmp[maxn];
vector<int> e[maxn];

void dfs(int u, int fa) {
    int maxval = 0, flag = -1;
    for (auto to: e[u])
        if (to != fa) {
            dfs(to, u);
            if (flag == -1) {
                flag = 1;
                maxval = tmp[to];
            } else {
                maxval = min(tmp[to], maxval);
            }
        }
    if (flag == -1) {
        tmp[u] = a[u];
        return;
    }
    if (u == 1) {
        tmp[u] = a[1] + maxval;
        return;
    }
    if (a[u] >= maxval)
        tmp[u] = maxval;
    else
        tmp[u] = (a[u] + maxval) / 2;
}

int main() {
    int T;
    cin >> T;
    while (T--) {
        cin >> n;
        for (int i = 1; i <= n; i++)
            cin >> a[i], e[i].clear();
        for (int i = 2; i <= n; i++) {
            int x;
            cin >> x;
            e[i].push_back(x);
            e[x].push_back(i);
        }
        dfs(1, 0);
        cout << tmp[1] << endl;
    }
    return 0;
}


  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值