【題解】Music Festival(樹狀數組優化dp)
題意:有\(n\)種節目,每種節目有起始時間和結束時間和權值。同一時刻只能看一個節目(邊界不算),在所有種類都看過至少一遍的情況下最大收益
設\(dp(s,i)\)表示已經看過\(s\)集合中的節目,且看過的節目的結束時間是\(i\)的最大收益。
轉移:
\[
dp(s,e[t].r)=\max(dp(s,k),dp(s-e[t].id,k))+e[t].val,k\le e[t].l
\]
由於\(O(m^3)\)不能過1000,但可以看到轉移是一段前綴,所以直接樹狀數組優化就好。
注意轉移的順序,可以發現\(r\)可以作爲轉移狀態。可能會有r相同的情況,但不影響答案。
複雜度\(O(m^2\log m)\)
//@winlere
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std; typedef long long ll;
inline int qr(){
register int ret=0,f=0;
register char c=getchar();
while(!isdigit(c))f|=c==45,c=getchar();
while(isdigit(c)) ret=ret*10+c-48,c=getchar();
return f?-ret:ret;
}
const int maxn=86405;
const int inf=0x3f3f3f3f;
int dp[1<<10|1][maxn];
struct E{
int l,r,id,val;
inline bool operator <(const E&a)const{return r<a.r;}
}e[1001];
int n,cnt,len;
inline int que(const int&pos,const int*a){
int ret=-inf;
for(int t=pos;t>0;t-=t&-t) ret=max(ret,a[t]);
return ret;
}
inline void upd(const int&pos,const int&tag,int*a){
for(int t=pos;t<=len;t+=t&-t) a[t]=max(a[t],tag);
}
int main(){
#ifndef ONLINE_JUDGE
freopen("in.in","r",stdin);
//freopen("out.out","w",stdout);
#endif
n=qr();
memset(dp,0xcc,sizeof dp);
for(int t=1;t<=n;++t){
int m=qr();
for(int i=1,t1,t2,t3;i<=m;++i) t1=qr(),t2=qr(),t3=qr(),e[++cnt]={t1,t2,t,t3};
}
sort(e+1,e+cnt+1);
len=e[cnt].r+1;
memset(dp[0],0,sizeof dp[0]);
for(int t=1;t<=cnt;++t){
for(int s=0;s<1<<n;++s){
if(s&(1<<e[t].id>>1)){
int g=s^(1<<e[t].id>>1);
int f=max(que(e[t].l,dp[s]),que(e[t].l,dp[g]))+e[t].val;
upd(e[t].r,f,dp[s]);
}
}
}
int g=que(len,dp[(1<<n)-1]);
cout<<max(g,-1)<<endl;
return 0;
}