团队题目链接
王强的疑惑((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;
}