Codeforces Round 966 (Div. 3)(A-F题解)C++

A. Primary Task

        一道签到题,因为给的数据范围是1e5还算小,所以当做数字读取,分类讨论也是可以做出来的。当然,更加方便的还是利用stl里的string类,可以使用 substr 来取子段分析。

B. Seating in a Bus

        一道简单的模拟题,只需要开一个2e5的vis数据来确定那些位置上已经有人了就可以模拟出来。注意:数组要适当开大一点,第一个位置要空出,以免在访问时出现数组越界的情况。

C. Numeric String Template

        也是一道模拟题,解题逻辑在题目中已经提及:

首先,利用长度做一个快速的判断。

其次,相同数字对应的字符要一样;相同字符对应的数字要一样。

1 2 3 1 4

a b e a e

其中,1对应的字符都为a;但e对应的数字不同,所以该样例答案是NO

主要考察的点还是对于stl中map的基本运用。

map <int,char> mp1;

map <int,char> mp2;

mp1.find(a[i])==mp1.end()        //判断是否存在该key

mp1[a[i]]=s[i];                  //不存在赋值,存在就比较

D. Right Left Wrong

题目描述

        有一个数组a,其中每个数字对应一个"L"或者对应”R“,定义为字符串s。每次操作找到一组LR(s[le]=="L";s[ri]=='R';le<ri)将区间内的所有数字求和,然后这个区间所有的对应字符更改为’,‘        要求求出最大的和是多少。

样例

6//有几个元素                答案

3 5 1 4 3 2                     

L R L L L R                         18

2

2 8

L R                                 10

2

3 9

R L                                  0

5

1 2 3 4 5

L R L R R                          22=(3+4)+(1+2+3+4+5)

思路

        这道题有两个思路。

思路一:

        因为要求最值,第一时间就想到了DP和贪心。首先考虑到的是,如果只能选择一对LR对,如何选择可以使得sum最大。简单思考可以得到答案,选择最左边的L和最右边的R。

        这时候注意到,最外面一对LR对,对区间里面的字符是没有要求的,也就是说,区间内的元素中如果能够再找到一对LR对,就是在原来答案上加了一份(这也是为什么最后一个样例的答案是22而不是15)。那么这里就可以理解为,每次找到最外面一个LR,然后把外面的部分不要了,在里面继续去找一对LR(也就是最优子结构)。那么这种情况就明显要使用到双指针,框定一个区间范围(l=0,r=n-1)。

        由于每次要对一个区间里的元素求和,所以要利用到前缀和快速求区间和,不然会超时。

思路二:(官方解法)

        由于一个数会出现多次,考虑这个数的权重(即出现次数)。既然要出现,必然是出于一个LR片段的中间,所以转换到 i-th 个数被多少个LR对包住。

        比对 i 号位置左边L个数,右边R个数,即可得到答案(第i号位置也要考虑)。LR对个数为min(cntL,cntR);

收获

        求最值的时候考虑到贪心和dp。这道题正向逻辑其实是,找到最里面的LR对,sum后变成’,‘然后每次向外扩一个LR对。但在实际实现的时候是从最外面开始找。

        如果从思路二的角度来说,由于一个元素可能被计算到多次,那么能否找到每个元素被计算到的次数,也就是找到每个数的权值。

ac代码(思路一)

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5;
long long b[N];
int main()
{
	int t,n,a[N];
	char s[N];
	cin>>t;
	while(t--){
		cin>>n;
		for(int i=1;i<=n;i++){
			cin>>a[i];
		}
		for(int i=1;i<=n;i++){
			cin>>s[i];
		}
		b[0]=0;
		for(int i=1;i<=n;i++){
			b[i]=b[i-1]+a[i];
		}
		
		long long ans=0;
		int le=1,ri=n;
		while(le<ri){
			while(le<=n && s[le]!='L'){
				le++;
			}
			while(ri>0 && s[ri]!='R'){
				ri--;
			}
			if(le<ri && le<=n && ri>0){
				ans=ans+b[ri]-b[le-1];
			}
			le++;
			ri--;
		}
		cout<<ans<<endl;
		
	}
}

E. Photoshoot for Gorillas

题目描述

        有一个n*m的矩形,k*k的范围。(可以放到矩形里面)矩形内每一个点都有分数,分数的值为所有能放进矩形中的k*k正方形形里面,覆盖到这个点的个数。

        另外有一个数组a,里面有w个正整数;要把这些数字放进矩形,每次操作会得到一个分数,分数值=ai*矩形分数。求最终得到的最大得分是多少

思路

        跟D题的思路二有点相似。主要难点在于求得矩阵中每个点的分数,即有多少个k*k可以包含在里面。

        在做到二维的题目时,最首先就是分成x,y轴分开讨论再中和。当分开讨论的时候,这道题的二维就转换成了两个一维问题,一段长度为n的线段中,x点上最多有多少个长度为k的线段。

那么有,最左边线段开头le=max(0,i-k+1)        最右边ri=min(i,n-k);        个数=(ri-le+1)     

        那么同理y轴方向,那么最后要怎么综合呢?       简单思考就能得到,两者应该相乘。

收获

        在做到二维问题的时候,首先考虑转换成两个一维问题解决,这在很多题目中都很适用。

ac代码

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5;
long long ans[N];
bool cmp(int a,int b){
	return a>b;
}
int main()
{
	int t,n,m,k,w;
	int a[N];
	cin>>t;
	while(t--){
		cin>>n>>m>>k;
		cin>>w;
		for(int i=0;i<w;i++){
			cin>>a[i];
		}
		int cnt=0;
		for(int i=0;i<n;i++){
			for(int j = 0;j<m;j++){
				int lex=max(0,i-k+1);
				int rix=min(i,n-k);
				int ley=max(0,j-k+1);
				int riy=min(j,m-k);
				ans[cnt]=(rix-lex+1)*(riy-ley+1);
				//cout<<ans[cnt]<<"	"; 
				cnt++;
			}
		}
		long long res=0;
		int i=0;
		sort(a,a+w,cmp);
		sort(ans,ans+cnt,cmp);
		while(w>0 && cnt>=0){
			//cout<<a[i]<<"	"<<ans[i]<<endl;
			res+=a[i]*ans[i];
			i++;
			w--;cnt--;
		}
		cout<<res<<endl;
	}
}

  • 12
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Codeforces Round 894 (Div. 3) 是一个Codeforces举办的比赛,是第894轮的Div. 3级别比赛。它包含了一系列题目,其中包括题目E. Kolya and Movie Theatre。 根据题目描述,E. Kolya and Movie Theatre问题要求我们给定两个字符串,通过三种操作来让字符串a等于字符串b。这三种操作分别为:交换a中相同位置的字符、交换a中对称位置的字符、交换b中对称位置的字符。我们需要先进行一次预处理,替换a中的字符,然后进行上述三种操作,最终得到a等于b的结果。我们需要计算预处理操作的次数。 根据引用的讨论,当且仅当b[i]==b[n-i-1]时,如果a[i]!=a[n-i-1],需要进行一次操作;否则不需要操作。所以我们可以遍历字符串b的前半部分,判断对应位置的字符是否与后半部分对称,并统计需要进行操作的次数。 以上就是Codeforces Round 894 (Div. 3)的简要说明和题目E. Kolya and Movie Theatre的要求。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [Codeforces Round #498 (Div. 3) (A+B+C+D+E+F)](https://blog.csdn.net/qq_46030630/article/details/108804114)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [Codeforces Round 894 (Div. 3)A~E题解](https://blog.csdn.net/gyeolhada/article/details/132491891)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值