解题报告3.16

本文介绍了四个编程问题的解法,涉及小根堆操作用于调整数列,最小代价路径搜索,差分数组优化加法序列,以及在二维空间中构建连通图的最小代价。
摘要由CSDN通过智能技术生成
A. 偷懒的小X(lazy)

题目大意:给出一个长度为n的数列,要求将答案数列按顺序放进小根堆中。

解法:分治。选择较小段[L+1,mid]放入右儿子2*p+1,选择较大段[mid+1,L]放入小儿子

#include<bits/stdc++.h>
#define int long long


#define go(p)  int ls=p<<1,rs=p<<1|1;


using namespace std;

const int N = 1e6 + 10;

int n,a[N],b[N],t[N],root;

void dfs(int p,int l,int r){
	t[p]=a[l];
	if(l==r)  return;
	int mid=l+r>>1;
	dfs(p<<1,mid+1,r);dfs(p<<1|1,l+1,mid);
}
signed main(){
	cin>>n;
	for(int i=1;i<=n;i++)  cin>>a[i];
	sort(a+1,a+n+1);
	dfs(1,1,n);
	for(int i=1;i<=n;++i)  cout<<t[i]<<" ";
	return 0;
}
B. 渡河(river)

题目大意:给出若干个点,求走到地图边界的最小代价。其中从0-1贡献+1

解法:从边界往中间搜,记录到每个点的最小值

#include<bits/stdc++.h>
#define int long long

#define go(p)  int ls=p<<1,rs=p<<1|1;

using namespace std;

const int N = 1e3 + 10;
const int dx[8] = { 1, 0, -1, 0, 1, 1, -1, -1 };
const int dy[8] = { 0, 1, 0, -1, 1, -1, 1, -1 };
int a[N][N];
int n,Q;
int b[N][N],v[N][N],dis[N][N];

struct node{
	int x,y;
}d[N];
int qx[N*N],qy[N*N];
void bfs(int x, int y, int z) {
    qx[1] = x, qy[1] = y;
    int head = 1, tail = 1, ans = 2147483647;
    while (head <= tail) {
        for (int j = 0; j < 8; ++j) {
            int X = qx[head] + dx[j], Y = qy[head] + dy[j];
            if (b[X][Y] && !v[X][Y] && a[X][Y] == z)
                v[X][Y] = 1, qx[++tail] = X, qy[tail] = Y;
            else if (!b[X][Y])
                ans = min(ans, dis[X][Y] + a[X][Y]);
        }
        ++head;
    }
    for (int i = 1; i <= tail; ++i) b[qx[i]][qy[i]] = 0, dis[qx[i]][qy[i]] = ans;
}
void solve(){
	int bx,by;
	cin>>bx>>by;
	cout<<dis[bx][by]<<" ";
}
signed main(){
	cin>>n>>Q;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			char c;
			cin>>c;a[i][j]=c-48;
			b[i][j]=1;
		}
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
		    if(b[i][j])
		      bfs(i,j,a[i][j]);
		}
	}
	while(Q--)  solve(); 
	return 0;
}

C. 进击的巨人

题目大意:求经过m次加法后的数列最小值

解法:差分板子

#include<bits/stdc++.h>
#define int long long

#define go(p)  int ls=p<<1,rs=p<<1|1;

using namespace std;

const int N = 1e6 + 10;
int n,m,a[N],s[N];

void insert(int l,int r,int p){
	s[l]+=p;s[r+1]-=p;
}
signed main(){
	ios::sync_with_stdio(false);
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		insert(i,i,a[i]);
	}  
	for(int i=1,l,r,k;i<=m;i++){
		cin>>l>>r>>k;
		insert(l,r,k);
	}
	for(int i=1;i<=n;i++)  s[i]+=s[i-1];
	for(int i=1;i<=n;i++)  cout<<s[i]<<" ";
	return 0;
}
D. 电缆建设

题目大意:给出若干个分布在两个竖直平面上的点,求连成连通图的最小代价

解法:将每个点与它相邻的点和另外平面的最近的两个距离点连有向边,在图上跑最小生成树

​
#include<bits/stdc++.h>

using namespace std;

const int N = 2e6 + 10;

int n,m,Lx,Rx,d,cnt,cx[N];

int read(){
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-')  f=-1;  
		ch=getchar();
	}
	while(ch>='0'&&ch<='9'){
		x=x*10+ch-48;ch=getchar();
	}return x*f;
} 
struct node{
	int x,y;
	double val;
}e[N<<2]; 
struct num{
	double x,y;
}a[N];
double dis(double bx,double by,double ex,double ey){
	return sqrt((bx-ex)*(bx-ex)+(by-ey)*(by-ey));
}
void add(int X,int Y){
	e[++cnt]={X,Y,dis(a[X].x,a[X].y,a[Y].x,a[Y].y)};
}
void build(){
	for(int i=2;i<=n;i++)  add(i-1,i);
	for(int i=n+2;i<=d;i++)  add(i-1,i);
	for(int i=1;i<=n;i++){
		int p=lower_bound(cx+1,cx+m+1,a[i].y)-cx;p+=n;
		if(p-1>=n+1)  add(i,p-1);
		if(p+1<=d)  add(i,p+1);
		add(i,p);
	}
}
int fa[N<<2];
int find(int x){
	if(fa[x]!=x)  return fa[x]=find(fa[x]);
	else return x; 
}
inline bool cmp(node p,node q){
	return p.val<q.val;
}
void solve(){
	double ans=0;int tot=0;
	for(int i=1;i<=d;i++)  fa[i]=i;
	sort(e+1,e+cnt+1,cmp);
	for(int i=1;i<=cnt;i++){
		int fx=find(e[i].x),fy=find(e[i].y);
		if(fx==fy)  continue;
		++tot;fa[fx]=fy;ans+=e[i].val;
		if(tot==d-1)  break;
	}
	printf("%.2f",ans);
}
int main(){
	n=read();m=read();Lx=read();Rx=read();
	int sumy=0;d=n+m;
	for(int i=1,k;i<=n;i++){
		k=read();sumy+=k;
		a[i]={Lx,sumy};
	}sumy=0;
	for(int i=1,k;i<=m;i++){
		k=read();sumy+=k;
		a[n+i]={Rx,sumy};cx[i]=sumy; 
	}
    build();
    solve();
	return 0;
}

​

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值