列表

详情


NC20552. [HNOI2013]旅行

描述

在遥远的HX国,住着一个旅行家小L,他希望骑着他的自行车游遍全国。在这个国家中,每个城市都有一个编号,共有n个城市,编号从1到n。

有的城市没有小L想去的景点,而有的城市有且仅有一个小L想去的景点,所有的城市都是这两种情况之一,小L非常热爱信息学,他编写程序给他的旅行安排了一条最短路线以到达所有他想去的景点(所以的通知旅行线路上城市编号是乱序的):他第1个到达的城市编号为a1,第i个到达的城市编号为ai,最后到达城市an结束这次旅行。小L希望用恰好的m个月(m<n)的时间完成这次旅行,所以他需要制定一个理性的旅游计划。

当他抵达一个城市时,如果这个城市有他想要去的景点,他会因此获得1点快乐值;但是若到达的城市没有他想去的景点,他会因旅途的疲惫得到1点的疲劳值:一个月的时间足够他游玩任意多个城市,但他也希望拿出一点时间来休息。他每个月总是在本月所到达的最后一个城市休息(但如果这个城市有景点,那么小L总会游玩这个景点再休息)。当然,小L希望每个月都能有一定的旅行任务。即便这个月他所到达的城市中并没有他想去的的景点,换句话说,每个月他都会至少到达一个新的城市。

小L无法自己安排旅行计划,所以求助于你。你需要告诉他一个序列:x1.x2......xm

xi表示小L第i个月休息时。他所在的城市编号:由于他最后一个月必须完成他的旅行,所以xm肯定等于an,例如,设n=5,m=3,(a1,a2,a3,a4.a5)=(3,2,4,1,5),(x1,x2,x3)=(2,1,5),这意味着:第1个月先后到达3号和2号城市,并在2号城市休息:第2个月先后到达4号和1号城市,并在一号城市休息:第3个月到达第5号城市,并在第5号城市休息。

这样的方案序列有很多种,设每种方案序列中第i个月旅行中当月获得的快乐值于疲劳值的绝对值为di,设第k种方案序列中求出的d1,d2......dm这个m值的最大值为ck,小L希望所选择的方案序列的ck在所有方案序列中是最小的。

事实上,可能有多个方案序列的ck达到并列最小值。由于小L喜爱编程,他患上了一定的强迫症(虽然他自己认为他的强迫症让他炫的发黄),他希望给他的序列是这多个方案中字典序最小的。

Tips:比较两个序列字典序即比较第一个不相同数字的大小,如1,2,3,4<1,2,4,3

输入描述

第一行为两个空格隔开的正整数n, m,表示旅行的城市数与旅行所花的月数。
接下来n行,其中第i行包含两个空格隔开的整数Ai和Bi,Ai表示他第i个去的城市编号。Bi为0或1;如果Bi=0则表示城市Ai没有小L想去的景点,如果Bi=1则表示城市Ai有小L想去的景点, Ai两两不同且有1 ≤ Ai ≤ N,即{Ai}为1,2....N的一个排列。 例如{2,1,3,4...N} 
N ≤ 500000,M ≤ 200000

输出描述

t仅包括一行,包含m个空格隔开的正整数X1,X2...Xm,t仅包括一行,包含m个空格隔开的正整数X1,X2...Xm,为给小L安排的旅行计划对应的路线。为给小L安排的旅行计划对应的路线。

示例1

输入:

8  3
2  0
3  1
4  1
1  0
5  0
6  1
7  1
8  0

输出:

1 6 8

说明:

第1个月得到2点快乐值与2点疲劳值,第2个月得到1点快乐值与1点疲劳值,第3 个月得到1点快乐值与1点疲劳值。3个月中疲劳值与快乐值差的最大值为0,达到所有方 案最小值。

可行方案有:

1 6 8 3 6 8 3 1 8 其中1 6 8字典序最小。

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++14(g++5.4) 解法, 执行用时: 96ms, 内存消耗: 21348K, 提交时间: 2019-10-29 22:17:36

// luogu-judger-enable-o2
// luogu-judger-enable-o2
//It is made by M_sea
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#define re register
using namespace std;

inline int read() {
    int X=0,w=1; char c=getchar();
    while (c<'0'||c>'9') { if (c=='-') w=-1; c=getchar(); }
    while (c>='0'&&c<='9') X=X*10+c-'0',c=getchar();
    return X*w;
}

const int N=500000+10;

int n,k,tot=0;
int id[N],t[N],sum[N],cnt[N];

struct node { int l,r,val; } w[N<<2]; 
struct Queue {
    int h,t,len;
    inline bool empty() { return !len; }
    inline void push_back(int x) {
        if (len) w[++tot]=(node){t,0,x},w[t].r=tot,t=w[t].r;
        else w[++tot]=(node){0,0,x},h=t=tot;
        ++len;
    }
    inline void pop_back() { t=w[t].l,--len; }
    inline void pop_front() { h=w[h].r,--len; }
    inline int front() { return w[h].val; }
    inline int back() { return w[t].val; }
    inline void push(int x) {
        while (!empty()&&id[w[t].val]>id[x]) pop_back();
        push_back(x);
    }
} A[N<<1],B[N<<2],*Q1=A+N,*Q=B+N;

int main() {
    n=read(),k=read();
    for (re int i=1;i<=n;++i) {
        id[i]=read(),t[i]=read();
        if (!t[i]) t[i]=-1;
    }
    for (re int i=n;i>=1;--i) sum[i]=sum[i+1]+t[i];
    for (re int i=n;i>=1;--i) cnt[i]=cnt[i+1]+(sum[i]==0);
    cnt[n+1]=-1;
    int ans=sum[1]?(abs(sum[1])+k-1)/k:(cnt[1]<k);
    if (!ans) {
        for (re int i=1,j=2;i<k;++i) {
            for (;cnt[j+1]>=k-i;++j) if (!sum[j+1]) Q[0].push(j);
            printf("%d ",id[Q[0].front()]); Q[0].pop_front();
        }
        printf("%d\n",id[n]);
    } else {
        int l=0; id[n+1]=n+1;
        for (re int i=2;i<=n;++i) Q[sum[i]].push_back(i-1);
        for (re int i=1;i<k;++i) {
            int s=n+1;
            for (re int j=sum[l+1]-ans;j<=sum[l+1]+ans;++j) {
                if ((abs(j)+k-i-1)/(k-i)>ans) continue;
                while (!Q[j].empty()&&n-Q[j].front()>=k-i) {
                    if (Q[j].front()>l) Q1[j].push(Q[j].front());
                    Q[j].pop_front();
                }
                while (!Q1[j].empty()&&Q1[j].front()<=l) Q1[j].pop_front();
                if (!Q1[j].empty())
                    if (id[s]>id[Q1[j].front()]) s=Q1[j].front();
            }
            l=s; printf("%d ",id[s]);
        }
        printf("%d\n",id[n]);
    }
    return 0;
}

C++11(clang++ 3.9) 解法, 执行用时: 96ms, 内存消耗: 21216K, 提交时间: 2019-02-25 17:47:37

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<iostream>
using namespace std;
#define ll long long
#define re register
#define file(a) freopen(a".in","r",stdin);freopen(a".out","w",stdout)
inline int gi()
{
	int f=1,sum=0;char ch=getchar();
	while(ch>'9' || ch<'0'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0' && ch<='9'){sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
	return f*sum;
}
const int N=500010;
struct data{int l,r,val;}w[N<<2];
int tot;
int n,m,a[N],b[N],sum[N],num[N];
struct Deque
{
	int st,ed,len;
	int empty(){return !len;}
	void push_back(int x){if(len)w[++tot]=(data){ed,0,x},w[ed].r=tot,ed=tot;else w[++tot]=(data){0,0,x},st=ed=tot;len++;}
	void pop_back(){ed=w[ed].l,len--;}
	void pop_front(){st=w[st].r,len--;}
	void push(int x){while(!empty() && a[w[ed].val]>a[x])pop_back();push_back(x);}
	int front(){return w[st].val;}
}A[N<<1],B[N<<2],*q1=N+A,*q=N+B;
int main()
{
#ifndef ONLINE_JUDGE
	file("travel");
#endif
	n=gi();m=gi();
	for(int i=1;i<=n;i++)
	{
		a[i]=gi(),b[i]=gi();
		if(!b[i])b[i]--;
	}
	for(int i=n;i;i--)
		sum[i]=sum[i+1]+b[i];
	for(int i=n;i;i--)
		num[i]=num[i+1]+(sum[i]==0);
	num[n+1]=-1;
	int ans=sum[1]?(abs(sum[1])+m-1)/m:(num[1]<m);
	if(!ans)
	{
//		puts("!");
		for(int i=1,j=2;i<m;i++)
		{
			for(;num[j+1]>=m-i;j++)
				if(!sum[j+1])q[0].push(j);
			printf("%d ",a[q[0].front()]);q[0].pop_front();
		}
	}
	else
	{
//		puts("!!");
		int l=0;a[n+1]=n+1;
		for(int i=2;i<=n;i++)q[sum[i]].push_back(i-1);
		for(int i=1;i<m;i++)
		{
			int s=n+1;
			for(int j=sum[l+1]-ans;j<=sum[l+1]+ans;j++)
			{
				if((abs(j)+m-i-1)/(m-i)>ans)continue;
				while(!q[j].empty() && n-q[j].front()>=m-i)
				{
					if(q[j].front()>l)q1[j].push(q[j].front());
					q[j].pop_front();
				}
				while(!q1[j].empty() && q1[j].front()<=l)q1[j].pop_front();
				if(!q1[j].empty())
					if(a[s]>a[q1[j].front()])s=q1[j].front();
			}
			l=s;printf("%d ",a[s]);
		}
	}
	printf("%d\n",a[n]);
	return 0;
}

上一题