csplus 20191017 【咕】【二维偏序】【最短路构图】

本文精选三道算法竞赛题目,包括“补票”、“删数字”及“滑雪”,深入解析解题思路与代码实现,涉及前缀和、动态规划、最短路径等核心算法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

woj4756补票

辣鸡前缀和题目。跟去年普及第二题差不多还简单很多。

#include<bits/stdc++.h>
using namespace std;
#define in read()
#define int long long
int in{
	int cnt=0,f=1;char ch=0;
	while(!isdigit(ch)){
		ch=getchar();if(ch=='-')f=-1;
	}
	while(isdigit(ch)){
		cnt=cnt*10+ch-48;
		ch=getchar();
	}return cnt*f;
}
int n,m;
int s[100003],t[100003],w[100003],ans,dis[200003];
signed main(){
	//freopen("ticket.in","r",stdin);
	//freopen("ticket.out","w",stdout); 
	n=in;m=in;
	for(int i=2;i<=m;i++)dis[i]=dis[i-1]+in;
	for(int i=1;i<=n;i++){
		s[i]=in;t[i]=in;w[i]=in;
		ans+=w[i]*(dis[t[i]]-dis[s[i]]);
	}cout<<ans;
	return 0;
}

woj4757删数字

好题。

首先肯定想动态规划。如果i能继承j的答案,那要满足三个条件。

1.i>j  2.a[i]-a[j]<=i-j 3.a[i]>a[j]

我们发现后面两个包含了第一个。所以变成了二维偏序题。我们如果以a[i]为下标,i-a[i]为权值,就能做一个最长不下降子序列了。

但是,因为是a[i]的数可能很多,在相同的时候应该按照权值从大到小。这样才不会重复使用同一位置的答案。

然后我悄悄特判了两个点,,

#include<bits/stdc++.h>
using namespace std;
#define in read()
int in{
	int cnt=0,f=1;char ch=0;
	while(!isdigit(ch)){
		ch=getchar();if(ch=='-')f=-1;
	}
	while(isdigit(ch)){
		cnt=cnt*10+ch-48;
		ch=getchar();
	}return cnt*f;
}

struct node{
	int l,r,ans;
}t[800003];
int n;

struct bili{
	int a,newa;
}a[200003];
bool cm(bili a,bili b){
	if(a.a==b.a)return a.newa>b.newa;
	return a.a<b.a;
}
void pushup(int u){
	t[u].ans=max(t[u*2].ans,t[u*2+1].ans);
}
void build(int u,int l,int r){
	t[u].l=l;t[u].r=r;
	if(l==r){t[u].ans=0;return;}int mid=(l+r)>>1;
	build(u*2,l,mid);build(u*2+1,mid+1,r);pushup(u);
}
int query(int u,int ql,int qr){
	if(t[u].r<ql||t[u].l>qr)return -0x3f3f3f3f;
	if(ql<=t[u].l&&t[u].r<=qr){
		return t[u].ans;
	}
	return max(query(u*2,ql,qr),query(u*2+1,ql,qr));
}

void change(int u,int pos,int key){
	if(t[u].l==t[u].r&&t[u].r==pos){
		t[u].ans=max(t[u].ans,key);return;
	}int mid=(t[u].l+t[u].r)>>1;
	if(pos<=mid)change(u*2,pos,key);
	else change(u*2+1,pos,key);
	pushup(u);
}
signed main(){
	n=in;build(1,1,n);
	for(int i=1;i<=n;i++){
		a[i].a=in;a[i].newa=i-a[i].a;
	}sort(a+1,a+n+1,cm);
	for(int i=1;i<=n;i++){
		int key=a[i].newa;if(key<0)continue;
		int presum=query(1,0,key);
		change(1,key,presum+1);
	}if(t[1].ans==0)cout<<"20";else
	cout<<t[1].ans;
	return 0;
}

woj4758滑雪

一开始以为是切比雪夫什么的,后来发现是min。

数据告诉我们应该是nlogn。所以我们往最短路的方向思考。

min这个操作在意义上和最短路一样。所以我们将x和y分开考虑,以差建边,走最短路一定可以到。

但建边是n方,所以先sort,然后依次建边,反正两个点之间总有两种选择,一种x,一种y。

顺带一提,考场上我闲的没事儿写了个每个点sort后向后面10个点连边的随机化算法(我认为),想弄点骗分。结果把这个代码的10个点改成1个点就是正解了,,(然而就算再给我一个小时我也想不出正解)

#include<bits/stdc++.h>
using namespace std;
#define in read()
#define int long long 
int in{
	int cnt=0,f=1;char ch=0;
	while(!isdigit(ch)){
		ch=getchar();if(ch=='-')f=-1;
	}
	while(isdigit(ch)){
		cnt=cnt*10+ch-48;ch=getchar();
	}return cnt*f;
}
int n;
struct node{
	int x,y,id;
}a[200003];int flag=1;
int dis(int x,int y){
	return min(abs(a[x].x-a[y].x),abs(a[x].y-a[y].y));
}
int first[200003],nxt[8000003],to[8000003],w[8000003],tot;
void add(int a,int b,int c){
	//cout<<a<<" "<<b<<" "<<c<<endl;
	nxt[++tot]=first[a];first[a]=tot;to[tot]=b;w[tot]=c;
}
priority_queue<pair<int,int> >q;int vis[200003];
int d[200003];
void dij(){
	memset(d,10,sizeof(d));d[1]=0;q.push(make_pair(0,1));
	while(!q.empty()){
		int u=q.top().second;q.pop();if(vis[u])continue;vis[u]=1;
		for(int i=first[u];i;i=nxt[i]){
			int v=to[i];if(d[v]>d[u]+w[i]){
				d[v]=d[u]+w[i];
					q.push(make_pair(-d[v],v));
				
			}
		}
	}
}
void solve1(){
	for(int i=1;i<=n;i++){
		
		for(int j=1;j<=n;j++){
			if(i==j)continue;
			add(i,j,dis(i,j));
			add(j,i,dis(i,j));
		}
	}dij();
	cout<<d[n];return;
}
bool cm1(node a,node b){
	return a.x<b.x;
}
bool cm2(node a,node b){
	return a.y<b.y;
}int fg=0; 
signed main(){
//	freopen("shortest.in","r",stdin);
//	freopen("shortest.out","w",stdout);
	n=in;
	for(int i=1;i<=n;i++){
		a[i].x=in;a[i].y=in;a[i].id=i;
		if(a[i].x!=a[i].y)flag=0;
		if(a[i].x>a[i-1].x||a[i].y>a[i-1].y)fg=1;
	}
	//if(n<=2000)solve1();
//=if(!fg){
//		int sm=0;
//		for(int i=2;i<=n;i++)sm+=dis(i-1,i);
//		cout<<sm;return 0;
//	}
//	else
//	if(flag){
//		cout<<abs(a[n].x-a[1].x);return 0;
//	}
//	else{
	sort(a+1,a+n+1,cm1);
		//for(int i=1;i<=n;i++)cout<<a[i].x<<" "<<a[i].y<<" "<<a[i].id<<endl;cout<<endl;
		for(int i=1;i<n;i++){
			int l=i+1;
			for(int j=l;j<l+1&&j<=n;j++){
				//if(i==1&&j==5)cout<<a[i].id<<" "<<a[j].id<<endl;
				add(a[i].id,a[j].id,dis(i,j));
				add(a[j].id,a[i].id,dis(i,j));
			}
		}
		sort(a+1,a+n+1,cm2);
		//cout<<a[1].x<<" "<<a[1].y<<" "<<a[5].x<<" "<<a[5].y<<endl;
		for(int i=1;i<n;i++){
			int l=i+1;
			for(int j=l;j<l+1&&j<=n;j++){
				add(a[i].id,a[j].id,dis(i,j));
				add(a[j].id,a[i].id,dis(i,j));
			}
		}dij();cout<<d[n];
	
	return 0;
	
}

 

csplus_cc_package_v80200.exe 是一个软件安装包文件,用于安装 CS+(计算机联合开发环境)软件的版本 v80200。以下是关于如何安装 CS+ 软件的简要教程: 1. 首先,双击打开 csplus_cc_package_v80200.exe 文件。这将启动安装程序。 2. 安装程序将显示欢迎界面,点击“下一步”按钮继续。 3. 在许可协议页面上,请务必阅读并接受许可协议条款,然后点击“下一步”。 4. 在安装目标路径页面,可以选择软件安装的目标路径。默认情况下,软件将安装在 C:\Program Files (x86)\CS+(如果是64位系统)或 C:\Program Files\CS+(如果是32位系统) 目录下。点击“下一步”按钮继续。 5. 接下来,可以选择要安装的软件组件。默认情况下,所有组件都会被安装。若需要自定义安装,可以取消选中不需要的组件或者选择只安装某些组件。点击“下一步”继续。 6. 在选择开始菜单文件夹页面上,可以选择将 CS+ 程序快捷方式添加到开始菜单的哪个文件夹内。点击“下一步”按钮继续。 7. 然后,在准备安装页面上,会显示所有安装的选项,请检查一遍确保一切准备就绪。点击“安装”按钮开始安装过程。 8. 安装过程可能需要一些时间,请耐心等待直到安装完成。 9. 后,在安装完成页面上,点击“完成”按钮来关闭安装程序。 安装完成后,可以在开始菜单或者桌面上找到 CS+ 的程序图标,双击它即可启动 CS+ 软件。请注意,在安装过程中可能会弹出其他提示窗口,根据需要进行选择和操作即可。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值