bzoj1150

这题调了我3小时…
显然只选相邻的两个楼,因为线路之间不能相交(比如说(1,3),(2,4)可以优化为(1,2)(3,4))所以如果选了(1,4)那么1和4之间的点都不会被用到(不然一定和(1,4)相交)而(1,2)肯定比(1,4)短,这么一来只选相邻

a_i表示第i个楼与第i+1个楼的距离设i时a_i取最小时的i 根据题意选了a_i就不能选a_(i-1),a_(i+1) 所以在选了a_i后删去a_i,a_i-1,a_i+1并加入a_(i+1)+a_(i-1)-a_i,如果后面选了新加的就表示不应选a_i而应a_(i-1)和a_(i+1),因为a_i最小所以旁边两个要么同时选要么同时不选

边界要特殊考虑 如果1比2小就直接确定选2不选1 因为选了2以后能选到的选了1也都能选到

代码

#include<iostream>
#include<cstdio>
 
using namespace std;
int n,k;
int prv[100005],nxt[100005],pos[100005];
struct node
{
    int v,x;
}h[100005];
int tot;
void up(int p)
{
    while(p>1)
    {
        if(h[p>>1].v>h[p].v)
        {
            pos[h[p>>1].x]=p;
            swap(h[p>>1],h[p]);
            p>>=1;
        }else break;
    }
    pos[h[p].x]=p;
}
void down(int p)
{
    int s=2*p;
    while(s<=tot)
    {
        if(s<tot&&h[s+1].v<h[s].v)++s;
        if(h[p].v>h[s].v)
        {
            pos[h[s].x]=p;
            swap(h[p],h[s]);
            p=s;
            s=2*p;
        }else break;
    }
    pos[h[p].x]=p;
}
void inst(int x,int y)
{
    h[++tot].v=x;
    h[tot].x=y;
    up(tot);
}
void rmov(int p)
{
    h[p].v=2e9;
    down(p);
}
int main()
{
    scanf("%d%d",&n,&k);
    int u,v;
    scanf("%d",&u);
    for(int i=1;i<n;++i)
    {
        scanf("%d",&v);
        prv[i]=i-1,nxt[i]=i+1;
        inst(v-u,i);
        u=v;
    }
    int ans=0;
    for(int i=1;i<=k;++i)
    {
        ans+=h[1].v;
        int t=h[1].x;
        if(prv[t]==0)
        {
            rmov(1);
            rmov(pos[nxt[t]]);
            prv[nxt[nxt[t]]]=0;
            continue;
        }
        if(nxt[t]==n)
        {
            rmov(1);
            rmov(pos[prv[t]]);
            nxt[prv[prv[t]]]=n;
            continue;
        }
        int a=nxt[t],b=prv[t];
        nxt[t]=nxt[a];prv[nxt[a]]=t;
        prv[t]=prv[b];nxt[prv[b]]=t;
        h[1].v=h[pos[a]].v+h[pos[b]].v-h[pos[t]].v;
        down(1);
        rmov(pos[a]);
        rmov(pos[b]);
    }
    printf("%d\n",ans);
    return 0;
}

update:
又写了一个 不用手写堆的(加个vis数组)

#include<iostream>
#include<cstdio>
#include<queue>

using namespace std;
int n,k;
int a[100005],prv[100005],nxt[100005];
bool vis[100005];
 
priority_queue<pair<int,int> >q;

int main()
{
	scanf("%d%d",&n,&k);
	for(int i=1;i<=n;++i)
	{
		scanf("%d",&a[i]);
		a[i-1]=a[i]-a[i-1];
	}
	for(int i=1;i<n;++i)prv[i]=i-1,nxt[i]=i+1,q.push(make_pair(-a[i],i));
	
	int ans=0;
	while(k--)
	{
		pair<int,int>tp=q.top();
		q.pop();
		int l=-tp.first,x=tp.second;
		if(vis[x])
		{
			++k;
			continue;
		} 
		ans+=l;
		if(prv[x]==0)
		{
			vis[nxt[x]]=true;
			prv[nxt[nxt[x]]]=0;
		}
		else if(nxt[x]==n)
		{
			vis[prv[x]]=true;
			nxt[prv[prv[x]]]=n;
		}
		else
		{
			a[x]=a[prv[x]]+a[nxt[x]]-a[x];
			vis[prv[x]]=vis[nxt[x]]=true;
			q.push(make_pair(-a[x],x));
			prv[nxt[nxt[x]]]=x;
			nxt[prv[prv[x]]]=x;
			prv[x]=prv[prv[x]];
			nxt[x]=nxt[nxt[x]];
		}
	}
	printf("%d\n",ans);
	return 0 ;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
BZOJ 2908 题目是一个数据下载任务。这个任务要求下载指定的数据文件,并统计文件中小于等于给定整数的数字个数。 为了完成这个任务,首先需要选择一个合适的网址来下载文件。我们可以使用一个网络爬虫库,如Python中的Requests库,来帮助我们完成文件下载的操作。 首先,我们需要使用Requests库中的get()方法来访问目标网址,并将目标文件下载到我们的本地计算机中。可以使用以下代码实现文件下载: ```python import requests url = '目标文件的网址' response = requests.get(url) with open('本地保存文件的路径', 'wb') as file: file.write(response.content) ``` 下载完成后,我们可以使用Python内置的open()函数打开已下载的文件,并按行读取文件内容。可以使用以下代码实现文件内容读取: ```python count = 0 with open('本地保存文件的路径', 'r') as file: for line in file: # 在这里实现对每一行数据的判断 # 如果小于等于给定整数,count 加 1 # 否则,不进行任何操作 ``` 在每一行的处理过程中,我们可以使用split()方法将一行数据分割成多个字符串,并使用int()函数将其转换为整数。然后,我们可以将该整数与给定整数进行比较,以判断是否小于等于给定整数。 最后,我们可以将统计结果打印出来,以满足题目的要求。 综上所述,以上是关于解决 BZOJ 2908 数据下载任务的简要步骤和代码实现。 希望对您有所帮助。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值