【NOIP2015模拟11.3】备用钥匙
2016-04-18 20:40
253 查看
Description
你知道Just Odd Inventions社吗?这个公司的业务是“只不过是奇妙的发明(Just Odd Inventions)”。这里简称为JOI社。JOI社有N名员工,编号从1到N。所有员工的工作时间从时刻0持续到时刻M,时刻0和时刻M的时候,所有员工都必须在公司内。
某天,出于巧合,JOI社的每个员工都要出行恰好一次。员工i(1<=i<=N)在时刻Si离开公司,时刻Ti回到公司。同一时刻不会同时有两名以上的员工离开或回到公司。
JOI社的入口处有一扇巨大的门,员工只能通过这扇门离开或回到公司。门上挂着一把锁,从公司内部可以任意开锁或上锁,但从公司外部只有持有备用钥匙的人才能开锁或者上锁。时刻0时,锁是锁上的。
每个社员在回到公司的时候,都必须能够进入公司。换句话说,对于任意1<=i<=N,要么员工i持有备用钥匙,要么时刻Ti时门是开着的,否则是不被允许的。员工回到公司的时候,或者携带备用钥匙的员工离开公司的时候,可以选择锁门或不锁。没有携带备用钥匙的员工离开公司的时候没有办法锁门。
JOI社的社长决定把备用钥匙交给N个员工中的K个人。为了避免钥匙的丢失,员工之间不允许借用钥匙。此外,JOI社的社长很重视时间效率,因此每个员工在离开或回到公司的时刻以外,不允许开锁或者上锁。
出于安全的考虑,社长希望上锁的时间越长越好。现在他将员工出入公司的信息和准备交给员工的钥匙数量告诉了你,请你求出在能使所有员工回到公司的时候都能进入公司的大门的前提下,上锁的时间最长是多少。
solution
这一题的解法特殊,首先对于两个相邻的时间点,有4种情况:
第一种:左出右出
只需要左端点那个人带钥匙该区间便可取。
第二种:左出右进
两人都带钥匙该区间便可取。
第三种:左进右出
都不用拿,直接计入答案。
第四种:左进右进
右端点那个人带钥匙该区间便可取
我们发现,有些时段的取或不取只取决于一个点,相当于只要这个人有钥匙他就有一定的贡献,所以每个人都有一个贡献值,
而对于那些两个都取了才有贡献的,我们可以连一条边,这样相当于如选我和我连边的点就有额外的贡献值,而且连得边一定是一条链,
那我们就可以把题目转换成:选每个点都有贡献值,而选了当前点又选了上一个点又另外奖励,
于是就可以设DP:f[i][j]表示做到点i,选了j个,
转移:f[i][j]=max(max(f[1~(i-2)][j-1]),f[i-1][j-1]+v[i])+p[i];
显然max(f[1~(i-2)][j-1])可以开数组优化,所以转移复杂度O(1),
Code
#include<iostream> #include<cstdio> #include<cstdlib> #include<cmath> #include<cstring> #include<algorithm> #define fo(i,a,b) for(int i=a;i<=b;i++) #define fo1(i,a,b) for(int i=a;i>=b;i--) //#define read(a) scanf("%d",&a) using namespace std; typedef long long LL; const int N=2500,maxlongint=2147483640; const LL INF=9223372036854775800; int read(int &n) { char ch=getchar(); while((ch!='-')&&((ch<'0')||(ch>'9')))ch=getchar(); int q=0,w=1;if(ch=='-')w=-1,ch=getchar(); while(ch>='0' && ch<='9')q=q*10+ch-48,ch=getchar();n=q*w;return n; } int m,n,ans,mt; struct qw { int s,t,n;//0:in }a1[N*2]; struct qqww{int p,ne,np;}a ; int f ,f0,F ; bool z ; bool PX(qw a,qw b){return a.t<b.t;} void add(int e,int e1) { f0++; f[f0][1]=e; fo(i,2,m) { if(f0>1)F[i-1]=max(F[i-1],f[f0-2][i-1]); f[f0][i]=max(f[f0-1][i-1]+e1,F[i-1]); if(f[f0][i])f[f0][i]+=e; } } void dfs(int q) { z[q]=1; if(a[q].ne && a[q].ne!=q)dfs(a[q].ne); add(a[q].p,a[q].np); } int main() { freopen("key.in","r",stdin); freopen("key.out","w",stdout); int q,w; read(n);read(mt);read(m); fo(i,1,n) fo(j,0,1)read(a1[i*2-j].t),a1[i*2-j].s=j,a1[i*2-j].n=i; sort(a1+1,a1+1+2*n,PX);ans=mt-a1[2*n].t+a1[1].t; fo(i,1,n*2-1) { q=a1[i].n,w=a1[i+1].n; if(a1[i].s && !a1[i+1].s)ans+=a1[i+1].t-a1[i].t; else if(!a1[i].s && !a1[i+1].s)a[q].p+=a1[i+1].t-a1[i].t; else if(a1[i].s && a1[i+1].s)a[w].p+=a1[i+1].t-a1[i].t; else if(q!=w) { a[w].ne=q; z[q]=1; a[w].np=a1[i+1].t-a1[i].t; }else a[q].p+=a1[i+1].t-a1[i].t; } fo1(i,n*2,1) if(a1[i].s) if(!z[a1[i].n]) { dfs(a1[i].n); } q=ans; fo(i,1,f0)ans=max(ans,q+f[i][m]); printf("%d\n",ans); return 0; }
相关文章推荐
- WEB网站常见的受攻击方式及预防手段
- LoadTypeLibEx
- spoj 16891 Character Patterns (Act 8)
- java内存区域与内存溢出异常
- 块级元素和内联元素区别
- android studio 签名并打包
- unity性能分析
- Messenger的基本用法(本质是跨APP的绑定服务)
- RC4加密算法的原理及实现
- Android布局之FrameLayout
- #ifndef 与 #program once 的区别
- 数据库系统概念学习04-数据模型
- LeetCode 第 231 题 (Power of Two)
- 编辑距离(动规例题)
- LeetCode 第 231 题 (Power of Two)
- 第八周上机实践项目——项目2-用对象数组操作长方柱类
- [杂记]国内某两家IT公司面试经验
- 匿名内部类
- 理解java异常处理机制
- ios 手势