Codeforces Round #310 (Div. 1) A B C

本文深入解析了三个复杂算法问题的解决策略,包括套娃问题、区间桥连接问题和巧克力网格问题。通过巧妙的算法设计,作者展示了如何在限制条件下找到最优解。文章详细解释了每种问题的思路、关键步骤和代码实现,旨在帮助读者理解和掌握复杂算法问题的求解方法。

Case of Matryoshkas

        n个套娃,套了几组,每秒能进行一次操作,简单地说是套只能套上单个,任意拆分,问全部套一起要多少秒。水题,就是题意坑。

#include <bits/stdc++.h>
using namespace std;

#define ll long long

int m[100010];
int cnt[100010];

int main(){
	int n,k;
	cin>>n>>k;
	int ans=0;
	int MAX=0;
	for(int i=1;i<=k;i++){
		scanf("%d",&m[i]);
		int pre=0;
		int num;
		for(int j=1;j<=m[i];j++){
			scanf("%d",&num);
			if(num==pre+1){
				cnt[i]++;
				pre=num;
			}
			MAX=max(MAX,cnt[i]);
		}
		ans+=m[i]*2;
		ans--;
	}
	ans-=MAX;
	ans-=(MAX-1);
	cout<<ans<<endl;
	
	return 0;
}

Case of Fugitive

        n个不相交区间,m个已知长度的桥。要求为每两个相邻区间跨上一座桥。输出任意解,无解输出0。

        贪心。每组相邻的区间,需要的桥的上下界是已知的,按上界升序排序,按顺序二分找最短的桥给它就行了。

#include <bits/stdc++.h>
using namespace std;

#define ll long long

const int maxn=200010;

ll l[maxn];
ll r[maxn];
ll a[maxn];
int n,m;

int ans[maxn];

struct node{
	ll MIN;
	ll MAX;
	int id;
	bool operator<(const node other)const{
		return MAX<other.MAX;
	} 
}seg[maxn];

struct Bridge{
	ll len;
	int id;
	bool operator<(const Bridge other)const{
		if(len!=other.len)return len<other.len;
		return id<other.id;
	} 
};

int main(){
	cin>>n>>m;
	
	for(int i=0;i<n;i++){
		scanf("%I64d%I64d",&l[i],&r[i]);
	}
	for(int i=0;i<n-1;i++){
		seg[i].MIN=l[i+1]-r[i];
		seg[i].MAX=r[i+1]-l[i];
		seg[i].id=i;
	}
	
	set<Bridge> Set;
	Bridge bb;
	for(int i=0;i<m;i++){
		scanf("%I64d",&bb.len);
		bb.id=i;
		Set.insert(bb);
	}
	sort(seg,seg+n-1);

	bool ok=1;
	for(int i=0;i<n-1;i++){
		Bridge tmp;	tmp.len=seg[i].MIN;
		tmp.id=-1;
		set<Bridge>::iterator it=Set.lower_bound(tmp);
		if((*it).len>seg[i].MAX){
			ok=0;
			break;
		}else{
			ans[seg[i].id]=it->id;
			Set.erase(*it);
		}
	}
	
	if(ok){
		cout<<"Yes"<<endl;
		for(int i=0;i<n-1;i++){
			printf("%d ",ans[i]+1);
		}
	}else{
		cout<<"No"<<endl;
	}
	
	return 0;
}

Case of Chocolate

        一块n*n的网格状巧克力,吃掉了下三角,只剩上三角(x+y<=n+1)。有q次操作,每次指定斜线上(x+y=n+1)的一个格子,开始向上或向左吃,吃到不能再吃为止。对每次询问回答吃了多少个格子。

        开始没注意看题,以为是二维线段树的神题,后来注意到开始吃的点位于斜线上。。。解题的关键是巧妙维护信息。把每次吃的格子的x坐标存到一个set里,对于每次询问,如果向上吃,就找x大的是哪一次,算y坐标的差;否则找x小的是哪一次,算x坐标的差。然后还要维护一下y或x,非常巧妙。。

#include <bits/stdc++.h>    
  
using namespace std;    

#define mp make_pair
#define pii pair<int,int>

const int maxn=200010;

int x[maxn];
int y[maxn];

int main(){
	int n,q;
	char dir[2];
	cin>>n>>q;
	set<pii> s;	set<pii>::iterator it;
	s.insert(mp(0,q+1));	x[q+1]=0;	y[q+1]=n+1;
	s.insert(mp(n+1,q+2));	x[q+2]=n+1;	y[q+2]=0;
	for(int i=1;i<=q;i++){
		scanf("%d%d%s",&x[i],&y[i],dir);
		if(dir[0]=='L'){	//找小的 
			it = s.upper_bound(mp(x[i]+1,0));
			it--;
		}else{				//找大的 
			it = s.lower_bound(mp(x[i],0));
		}
		if(it->first==x[i]){
			printf("0\n");
			continue;
		}
		s.insert(mp(x[i],i));
		if(dir[0]=='L'){
			printf("%d\n",x[i]-x[it->second]);
			x[i]=x[it->second];
		}else{
			printf("%d\n",y[i]-y[it->second]);
			y[i]=y[it->second];
		}
	}
	return 0;
}

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值