codeforces部分题题解2

contest:Codeforces Round #780 (Div. 3)

contest submissions:        ABC

contest standings:        4981

vp contest;

vp time:        2022/10/04

Problem - B - Codeforces

题目大意:意思就是说找两个下标使得i * j -k * (ai |aj )的值最大。

 思路:分析:
仔细观察k的范围,会发现k<=100;又显然1<=ai<=n,所以 ai | aj <=2 * n。i * j最大可达到n^2,而k*(ai | aj)最大也就是200 * n;显然,当n在一定大的时候,200*n所起的作用并不是很大,只需要在n一定大的时候遍历所有的n即可。那这个一定大的范围应该在哪里呢?我们记函数f( i , j )=i * j-k * (ai | aj).则f(n-1,n)=n * n-2 * k * n-n。我们需要找到可能的最小的i,使f(i, j)>f(n-1,n).假设ai=an=0,那么f(i,n)=i * n(此时i一定是最小的,因为被减数k * (ai | aj)为0,j为最大值n)。那么令 i * n>n * n-2 * k * n-n;
则i>n-2 * k-1。所以我们只需要从max(1,n-2 * k)开始遍历i即可得到答案。
效率:时间复杂度为O(k^2).这个题目还是着重考思维的。不过数据范围算是给了点提示在里面。

//因为k<100,1<=ai<=n,那么ai|aj<=2*n
//那么如果说i*j足够大的时候,200*n所起的作用也就不是很大了
//所以只要在
#include<bits/stdc++.h>
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;
		vector<int>a(n+1);
		for(int i=1;i<=n;i++)	cin>>a[i];
		long long ans=-1e18;
		int l=max(1,n-2*k);
		for(int i=l;i<=n;i++)
			for(int j=i+1;j<=n;j++)
				ans=max(ans,(long long )1*i*j-(long long)k*(a[i]|a[j]));
		cout<<ans<<endl;
	}	
	return 0;
} 

Problem - A - Codeforces

 题目大意:就是说每一次操作可以选择任意两个数,然后一个数加1,一个数减1,以求得最小序列。

思路:这个题目还是很明显的贪心题目,就是每次都尽量前面的数变小就好了,但是要非负,题目里面有要求。这个题居然还wa了一发,就是最后输出的那个for循环给错位置了,还是需要仔细一点。

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        int n,k;
        cin>>n>>k;
        int a[110];
        for(int i=1;i<=n;i++)    cin>>a[i];
        for(int i=1;i<n;i++)
        {
            if(k==0)    break;
            else
            {
                a[n]+=min(k,a[i]);
                if(k>=a[i])
                {
                    k=k-a[i];
                    a[i]=0;
                }
                else
                {
                    a[i]-=k;
                    k=0;
                }
            }
        }
        for(int i=1;i<=n;i++)    cout<<a[i]<<' ';
            cout<<endl;
    }
    return 0;
}





Problem - A - Codeforces

 题目大意:题目意思就是说有a个一块钱的币和b个两块钱的币,求最小而且不能表示出来的值。

思路:首先应该想到的是能不能表示1的问题,因为1是比较特殊,他不能被2表示呀,对吧,所以说首先就是要特判一下有没有1;其次就会发现除了1之外的所有数都可以通过1或者是2,或者是1和2同时用去表示出来,所以最小的就应该是a+2*b+1。这个题目还是很好想的。

#include<bits/stdc++.h>
using namespace std;
void solve()
{
	int a,b;
	cin>>a>>b;
	if(a==0)	cout<<1<<endl;
	else	cout<<2*b+1+a<<endl;
	return ;
}
int main()
{
	int t;
	cin>>t;
	while(t--)	solve();
	return 0;
 } 

Problem - B - Codeforces

 题目大意:意思就是说想要买一些类型的糖用来吃,但是呢每一次只会吃一颗,而且每次吃就只会吃当前数量最多的,如果说此时数量量最多的类型有很多种,就都能吃,而且不能够连续两天吃到同一种类型的糖,问是否可能就是在这些条件下说吃完所有的糖。

思路:麻了,阅读水平太差了,一直搞不清楚题目意思,最后这个含义还是猜出来的。其实也不难想到,就是说假如最大值 - 次大值大于等于2,就是不行的,因为你第二天就已经和第一天就是一样的了,如果说小于2,那么接下来你就可以去吃次大值,同样,在到达第三个值加入到这个循环里面来,以此类推,这样子所有的值都可以加入到循环里面来。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int a[200010];
void solve()
{
	int n;
	cin>>n;
	ll maxn=0;
	ll ans=0;
	for(int i=1;i<=n;i++)	cin>>a[i];
	sort(a+1,a+n+1);
	//int no=n,la=no-for(int i=1;i<=)
	if(n==1)
	{
		if(a[1]>=2)	cout<<"NO\n";
		else	cout<<"YES\n";
		return ;
	}
	if(a[n]-a[n-1]>=2)	cout<<"NO\n";
	else	cout<<"YES\n"; 
	//每次都是吃目前最多的
	//for(int i=n;i>1;i--)
	//{
		//其实主要看的就是最大的那个
		
//	}
}
int main()
{
	int t;
	cin>>t;
	while(t--)		solve();
	return 0;
}

Problem - C - Codeforces

题目大意:首先就是偶数串就是说对于a[2k-1]都有a[2k-1]==a[2k],然后给定一个串,每一次操作,你可以删除一个任意一个字符,求最少多少次可以使得字符串是一个偶数串。

思路:这个题目也是比较好想的,就是贪心,先出现的就直接匹配呗,这样子明显比其他的要好一些,这样子也可以留下更多的字符去匹配剩下的字符

#include<bits/stdc++.h>
using namespace std;
map<char,int>mp;
void solve()
{
	string s;
	cin>>s;
	mp.clear();
	s=' '+s;
	int ans=0;
	int last=1;
	for(int i=1;i<=s.size();i++)
	{
		if(mp[s[i]])
		{
			ans+=i-last-1;
			mp.clear();
			last=i+1;
		}
		else	mp[s[i]]=1;
	}
	if(last!=s.size())	ans+=s.size()-last;
	cout<<ans<<endl;
	return ;
}
int main()
{
	int t;
	cin>>t;
	while(t--)	solve();
	return 0;
}

注:对于STL可以多熟悉一下,mp.clear()可以清空所有匹配的值。

Problem - D - Codeforces

 题目大意:就是说给定一个序列,每次操作你可以删除最边上的元素,左边或者是右边都行,随便删除多少次,求序列乘积最大值,如果说序列为空,那么值就为1。

思路:偶数个负数相乘可以转化为正数,而奇数个负数只会让乘积变小,而0就会使得乘积归0.那么我们只是需要把序列以0为分界点去分开他,并且对子序列的负数数量进行判断如果说为偶数,那么整个序列相乘就可以是最大值,而如果说是奇数,那么就需要删除边上的一段以负数为分割点且乘积最小的值,才会使得剩下序列的值最大,而序列值大小,其实还是主要看绝对值为2的数的数量。

//因为乘以0就直接为0了,那所有的都功亏一篑了,所以我们分别考虑0所分开的那些区间
#include<bits/stdc++.h>
using namespace std;
int a[200010];
int cnt;//区间当中绝对值为2的个数,也只有2对结果有影响了 
int ansx,ansy,n;
void up(int l,int r)
{
	if(l>r)	return ;
	int t=0;
	//看区间内部有多少个绝对值为2的数
	for(int i=l;i<=r;i++)
		if(abs(a[i])==2)
			t++;
	if(t>cnt)
	{
		cnt=t;
		ansx=l-1;
		ansy=n-r;
	} 
	return ;
}
int cnt__(int l,int r)
{
	int sign=0;
	for(int i=l;i<=r;i++)
		if(a[i]<0)
			sign++;
	return sign;	
}
void cal(int l,int r)
{
//首先就是去计算一下区间内部负数的数量
	int sign=cnt__(l,r);
	if(sign%2==0)	up(l,r);//如果是偶数,就直接更新就好了
	else
	{
		//如果是奇数,就要看是删除前面一段还是后面一段了
		int id=l;
		while(a[id]>0)	id++;
		up(l,id-1);
		up(id+1,r);
		id=r;
		while(a[id]>0)	id--;
		up(l,id-1);
		up(id+1,r);
	} 
}
void solve()
{
	cin>>n;
	for(int i=1;i<=n;i++)	cin>>a[i];
	a[n+1]=0;
	ansx=n,ansy=0,cnt=0;
	//首先就是先把0分成的区间分开看
	for(int j=1,i=1;i<=n+1;i++)
	{
		if(a[i]==0)
		{
			if(i-1>=j)	cal(j,i-1);//计算区间的值
			j=i+1; 
		}
	}
	cout<<ansx<<' '<<ansy<<endl;
	return ; 
}
int main()
{
	int t;
	cin>>t;
	while(t--)	solve();
	return 0;	
} 

注意:对于需要重复进行的操作,可以写成函数形式,到时候直接调用就行,减少代码复杂度,还清晰一些,学着点。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值