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;
}