Codeforces Round #600 (Div. 2)

A:直接模拟,判断不相同的段是否小于1,且每段差值都相同,且a始终小于b。

B:也是直接模拟,注意要判断1,2,3个规则,不能漏。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
//typedef __int128 LL;
//typedef unsigned long long ull;
//#define F first
//#define S second
typedef long double ld;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
typedef pair<ld,ld> pdd;
const ld PI=acos(-1);
const ld eps=1e-9;
//unordered_map<int,int>mp;
#define ls (o<<1)
#define rs (o<<1|1)
#define pb push_back
#define in insert
const int seed=131;
const int M = 2e5+7;
/*int head[M],cnt;
struct EDGE{int to,nxt,val;}ee[M];
void add(int x,int y,int z){ee[++cnt].nxt=head[x],ee[cnt].to=y,ee[cnt].val=z,head[x]=cnt;}*/
int a[M],pre[M];
int z[M];
set<int>s,q;
int main()
{
	ios::sync_with_stdio(false);
  	cin.tie(0);
	int n;
	cin>>n;
	bool f=true;
	int sz=0,tp=0,k=0;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
		tp++;
		if(!f)continue;
		if(a[i]>0)
		{
			if(q.find(a[i])!=q.end())f=false;//规则1 
			else{
				s.in(a[i]);
				q.in(a[i]);
			}
		}
		else{
			if(s.find(-a[i])==s.end())f=false;//规则2 
			else{
				s.erase(-a[i]);
				if(s.empty())//规则3
				{
					z[++sz]=tp;
					tp=0;
					q.clear();
				}
			}
		}
	}
	if(!f||!s.empty())cout<<"-1"<<endl;
	else{
		cout<<sz<<endl;
		for(int i=1;i<=sz;i++)
		cout<<z[i]<<" ";
	}
	return 0;
}

C:有一个很明显的贪心策略,吃k个糖时,先选甜度最小的k个,然后把这k个糖中甜度最大的先吃,甜度小的后吃。

但这样处理k==1-n时明显会T。

这类题目我们考虑从k  ->  k+1结果会发生怎样的变化。

很明显,我们会再第一天吃甜度第k+1小的糖,然后把之前K个吃的顺序不变,往后+1.(注意是顺序+1,不是天数+1).

由于一天可以吃m个。

前m个直接一天吃完。

考虑第m+1个糖果,肯定是第一天吃甜度第2-m+1小的糖果,然后第二天吃甜度最小的糖果。

再考虑第m+2个糖果,肯定是第一天吃甜度第3-m+2小的糖果,然后第二天吃甜度第1-2小的糖果。

再考虑第m+3个糖果,肯定是第一天吃甜度第4-m+3小的糖果,然后第二天吃甜度第1-3小的糖果。

如果你在纸上画一下就会发现,每次都是把对应格子的糖果(有m个格子)给挤上去。

比如m=3,

k==3: 

一:1 2 3

k==4

二:1

一:4 2 3

k==5

二:1 2

一:4 5 3

k==6

 

二:1 2 3

一:4 5 6

k==6

三:1 

二:4 2 3

一:7 5 6

到这里就很显然了。

我们用d数组表示底的贡献,每次把对应的底的贡献加上即可。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
//typedef __int128 LL;
//typedef unsigned long long ull;
//#define F first
//#define S second
typedef long double ld;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
typedef pair<ld,ld> pdd;
const ld PI=acos(-1);
const ld eps=1e-9;
//unordered_map<int,int>mp;
#define ls (o<<1)
#define rs (o<<1|1)
#define pb push_back
#define in insert
const int seed=131;
const int M = 2e5+7;
/*int head[M],cnt;
struct EDGE{int to,nxt,val;}ee[M];
void add(int x,int y,int z){ee[++cnt].nxt=head[x],ee[cnt].to=y,ee[cnt].val=z,head[x]=cnt;}*/
ll a[M],d[M];
int main()
{
	ios::sync_with_stdio(false);
  	cin.tie(0);
	int n,m;
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	cin>>a[i];
	sort(a+1,a+1+n);
	int tp=0;
	ll ans=0;
	for(int i=1;i<=n;i++)
	{
		tp++;
		if(tp>m)tp=1;
		d[tp]+=a[i];
		ans+=d[tp];
		cout<<ans<<" ";
	}
	return 0;
}

D - Harmonious Graph

思路要清晰,这题就问你满足联通块中节点id最大减去最小等于联通块中节点个数-1.我们要加几条边才能满足这个条件。

首先,如果有一个联通块 1 , 2,7。怎么使它满足题意呢,我们先询问1-2是否联通,然后依次,发现1-3不连通。我们直接连1-3,让1所在的联通块与3联通,然后询问1-4是否联通,不联通的话再连1-4类推下去。

注意终点不是这个联通块初始的最大id,而是这个联通块实时的最大id(因为联通的过程可能会使最大id变大,比如连了1-3,但3与10联通,我们就要询问到1-10是否联通)。

有了上面的想法,我们就可以用并查集维护,联通块的大小,最大id,最小id。

最后,从id最小开始往上询问,(这样保证联通块最小id始终不变),如果当前id所在联通块还不满足题意,就像上面我们说的那样进行更新,直到n个点都满足题意即可。

 

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
//typedef __int128 LL;
//typedef unsigned long long ull;
//#define F first
//#define S second
typedef long double ld;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
typedef pair<ld,ld> pdd;
const ld PI=acos(-1);
const ld eps=1e-9;
//unordered_map<int,int>mp;
#define ls (o<<1)
#define rs (o<<1|1)
#define pb push_back
#define in insert
const int seed=131;
const int M = 2e5+7;
/*int head[M],cnt;
struct EDGE{int to,nxt,val;}ee[M];
void add(int x,int y,int z){ee[++cnt].nxt=head[x],ee[cnt].to=y,ee[cnt].val=z,head[x]=cnt;}*/
int fa[M],size[M];
int get(int x)
{
	if(x==fa[x])return x;
	return fa[x]=get(fa[x]);
}
int ma[M],mi[M];
void add(int x,int y)
{
	int gx=get(x),gy=get(y);
	if(gx!=gy)
	{
		fa[gx]=gy;
		ma[gy]=max(ma[gx],ma[gy]);
		mi[gy]=min(mi[gx],mi[gy]);
		size[gy]+=size[gx];
	}
}
int main()
{
	ios::sync_with_stdio(false);
  	cin.tie(0);
	int n,m,x,y;
	cin>>n>>m;
	for(int i=1;i<=n;i++)fa[i]=mi[i]=ma[i]=i,size[i]=1;
	for(int i=1;i<=m;i++)
	{
		cin>>x>>y;
		add(x,y);
	}
	int ans=0;
	for(int i=1;i<=n;i++)
	{
		int gi=get(i);
		if(ma[gi]-mi[gi]+1==size[gi])
		continue;
		int mx=ma[gi];
		for(int j=i;j<=mx;j++)
		{
			int gj=get(j);
			if(gi!=gj){
				ans++;
				add(j,i);
				gj=get(j);
				mx=max(mx,ma[gj]);
			}
		}
	}
	cout<<ans<<endl;
	return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值