Codeforces Round 860 (Div. 2)

Problem - D - Codeforces

思路:

  1. 只要数组同时存在正数与负数存在该排序存在
  2. 因为存在正负数,所以对于任意一个值都小于max。
  3. 那么我们可以排序后贪心每次都加一个小正数,直到不能再加就补一个大负数,然后就继续加正数,一直维持正数不超过即可
#include <bits/stdc++.h>
using namespace std;
#define ll     long long
#define int ll
int32_t main()
{
	std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	int t;
	cin>>t;
	while (t--)
		{
			int n,x;
			cin>>n;
			vector<int>zh,fu;//他们没人放0,用于确认是否正负数都存在
			for (int i=1; i<=n; ++i)
				{
					cin>>x;
					if (x>0)zh.push_back(x);
					else if (x<0)fu.push_back(x);
				}
			if (zh.empty()||fu.empty())//正负必须同时存在
				{
					cout<<"NO"<<endl;
					continue;
				}
			sort(zh.begin(),zh.end());
			sort(fu.begin(),fu.end());
			int i=0,j=0;
			int maxn=zh.back()-fu.front(),sum=0;
			vector<int>ans;
			while (i<(int)zh.size()&&j<(int)fu.size())
				{
					if (zh[i]+sum<maxn)//贪心加正数
						{
							ans.push_back(zh[i]);
							sum+=zh[i++];
						}
					else//不行补一个较大负数
						{
							ans.push_back(fu[j]);
							sum+=fu[j++];
						}
				}
			while (i<(int)zh.size())ans.push_back(zh[i++]);
			while (j<(int)fu.size())ans.push_back(fu[j++]);
			cout<<"YES"<<endl;
			while ((int)ans.size()<n)ans.push_back(0); //前面是没有存入0的,所以缺的话那就是0了
			for (auto &k:ans)cout<<k<<" ";
			cout<<endl;
		}
	return 0;
}

Problem - E - Codeforces

思路:

  1. 设dp[i]表示i~n的连续拼接子串(无法连续拼接,设为-1)
  2. maxn[i]表示在修改前可以取到的i~n区间的最多连续拼接子串数量,注意,不一定是到i~n连续,代表的是i或者i之后的dp[i]的最大值
  3. f[i]表示修改后(当然你也可以不用修改啦)可以取到的i~n的连续拼接子串最大值(这个必须是i~n连续了)
  4. 我们不难发现,答案只有0,1,2。
    1. 首先,如果a[i]=dp[i+1](即i+1~n连续且子串数量为a[i]),理想情况,不用修改
    2. 修改1次时,我们可以着眼于是修改a[i]的值还是修改(i+1,n)这个区间
      1. 如果修改a[i],那么你首先需要保证(i+1,n)连续,即dp[i+1]!=-1。那么修改a[i]=f[i+1]即可
      2. 如果修改区间(此时区间一定不连续,不然我修改a[i]不就好了),那你只要满足a[i]<=f[i+1],即修改后可以取到的最大f,那么可以一次操作结束(因为我们一部操作修改a[i+1]可以使得他跑到(i+1,n)任何一个位置,所以可以取值(1,f[i+1])
    3. 修改2次,不用说了
#include <bits/stdc++.h>
using namespace std;
#define ll               long long
#define endl             "\n"
#define int              long long
const int N = 3e5 + 10;
int dp[N];
int a[N],ans[N],maxn[N],f[N];
void mysolve()
{
	int n;
	cin>>n;
	for (int i=1; i<=n; ++i)cin>>a[i],dp[i]=-1,maxn[i]=f[i]=0;
	dp[n+1]=maxn[n+1]=f[n+1]=0;
	for (int i=n; i>=1; --i)
		{
			if (i==n)
				{
					if (a[i]==0)dp[i]=1;
				}
			else
				{
					if (dp[i+1]!=-1)//区间连续时
						{
							if (a[i]==dp[i+1])ans[i]=0;
							else ans[i]=1;
						}
					else
						{
							if (a[i]<=f[i+1])ans[i]=1;
							else ans[i]=2;
						}
					if (dp[min(n+1,i+a[i]+1)]!=-1&&i+a[i]<=n)dp[i]=dp[min(n+1,i+a[i]+1)]+1;//更新dp时,满足i+a[i]+1不超区间再加上他也是连续即可更新,否则是-1
				}
			maxn[i]=max(maxn[i+1],dp[i]);//更新maxn就是取(i,n)中的dp最大值
			f[i]=maxn[i+1]+1;//更新f就是你要么修改后最多加一步,要最多,这一步就到max。要么不修改
			if (a[i]+i+1<=n)f[i]=max(f[i],1+f[i+a[i]+1]);
		}
	for (int i=1; i<n; ++i)cout<<ans[i]<<" \n"[i==n-1];
}
int32_t main()
{
	std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	ll t;
	cin >> t;
	while (t--)
		{
			mysolve();
		}
	system("pause");
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值