【校内模拟】王强的疑惑

团队题目链接

王强的疑惑((math))

时限:(2s) 空间:(256MB)

【题目背景】

​ 在遥远的(mathcal{DeepDark})星系中,生活着一种神奇的生物——王(♂)强,他们鳝长于(AK) (OI) 比赛,在一个(mathcal{van})物复苏的季节,一只年轻的雄性王强开始了他的(AK)活动...

【题目描述】

(mathcal{DeepDark})星系中有(n)个星球在举行(OI)比赛,星球的名称分别是(1)号星球,(2)号星球……,(n)号星球,第(i)个星球的全球决赛叫做(IOI),由于每个星球的自转和公转时间不同,所以他们(OI)赛的时间也不同;

现在王(♂)强知道了每一场(OI)赛的开始时间(a_i)和结束时间(b_i),并且根据他往年(AK)的次数,预测了每个(OI)赛他(AK)的概率(p_i)

每个星球只有(1)场比赛,王(♂)强不能在同一时刻在两个星球上;

(♂)强一开始在(1)号星球上,而他从任意一个星球移动另一个星球需要(q)的时间;

现在王(♂)强想知道他该如何参加比赛,使他的期望(AK)场数最大。

【输入输出格式】

输入格式

第1行两个整数(n)(q)

接下来(n)行,第(i+1)行有两个整数和一个小数,

分别表示(TOI)的开始时间(a_i),结束时间(b_i)和王(♂)(AK)(IOI)的概率(p_i)

输出格式

第1行一个浮点数,表示王(♂)强最大期望能够(AK)的场数,保留三位小数

第2行输出王(♂)(AK)的星球编号,中间用空格隔开,数据保证只有一组解

【输入样例】

输入样例#1:

5 2
7 10 0.8123456789
2 5 0.223456789
6 9 0.83456789
3 6 0.3456789
8 10 0.756789

输入样例#2:

14 0
2 7 0.37
0 1 0.20
8 9 0.13
1 5 0.19
0 8 0.4
0 2 0.57
0 3 0.2
4 9 0.4
5 9 0.26
8 10 0.80
9 10 0.27
3 7 0.3
5 9 0.64
3 9 0.55

【输出样例】

输出样例#1:

1.102
4 5

输出样例#2:

1.740
6 1 10

【数据范围】

对于(100\%)的数据,(1leq nleq 10^6,0leq l_i< r_ileq 10^6,0leq p_ileq 1,0leq qleq10^5)

特殊限制:

测试点 (n) (q,p_i) 分值
1 (leq 15) (15)
2 (leq 15) (15)
3 (leq 1000) (q=1,p_i=0) (15)
4 (leq 1000) (15)
5 (leq 10^6) (20)
6 (leq 10^6) (20)

【题解】

显然这是一道递归(DP)题,

(dp_i)表示时间为(i)时的最大期望收益

考虑当区间(j)的右端点(c_j.r)等于(i)时,我们可以进行转移

(dp[i] = max ( dp[c_j . l] + c_j.w ))

我们可以将所有区间按照右端点排个序,然后枚举时间(i),进行(dp)

有一个细节是王♂强一开始在(1)号星球,在转移的时候特判一下即可

if(c[j].id==1){
    if(dp[i]<c[j].w) dp[i]=c[j].w;
    //...
}

显然每个(i)会被枚举到一次,每个区间会用到一次

(DP)的复杂度是(O(n+maxr))

但是(sort)(O(nlogn))

所以总的复杂度为(O(nlogn))

(mathcal{std})

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define N 1000010
int n,p,pre[N],ans[N],stack[N],top;
struct _OI{
    int l,r,id;
    double w;
} c[N];
double f[N];
bool cmp(_OI x,_OI y){
    return x.r<y.r;
}
int main()
{
    scanf("%d%d",&n,&p);
    int maxr=0;
    for(int i=1;i<=n;i++){
        scanf("%d%d%lf",&c[i].l,&c[i].r,&c[i].w);
        maxr=max(maxr,c[i].r);
        c[i].id=i;
    }
    sort(c+1,c+1+n,cmp);
    int j=1;
    for(int i=1;i<=maxr;i++){
        f[i]=f[i-1]; pre[i]=i-1;
        while(c[j].r==i){
			if(c[j].l>=p&&f[i]<f[c[j].l-p]+c[j].w){
	           	f[i]=f[c[j].l-p]+c[j].w;
	           	pre[i]=c[j].l-p;
	           	ans[i]=j;
	        }
        	if(c[j].id==1&&f[i]<c[j].w){
        		f[i]=c[j].w;
        		pre[i]=0;
        		ans[i]=j;
			}
            ++j;
        }
	}
    printf("%.3lf
",f[maxr]);
    int now=maxr;
    while(!ans[now]&&now) --now;
    while(now){
    	if(ans[now]) stack[++top]=c[ans[now]].id;
    	now=pre[now];
	}
	while(top){
		printf("%d ",stack[top]);
		--top;
	}
    return 0;
}
原文地址:https://www.cnblogs.com/yjkhhh/p/9909851.html