您的位置:首页 > 其它

P3802不死(二分答案+状压dp验证)

2017-10-07 16:17 281 查看
子曰:不睡觉就会死。

深信此话的LYM决定在本学期接下来的n节课上考虑一下睡觉的问题。LYM认为如果在一堂课上睡觉,身体的疲劳值就会下降,反之如果在一堂课上不睡觉,身体的疲劳值就会上升。而身体对疲劳的忍耐是有限度的,一旦疲劳值超过限度,LYM就会go die,于是他不得不在一些课上睡觉。注意,LYM的疲劳值只会在一节课上完后发生改变,如果上完最后一节课后,疲劳值超出了限度,LYM仍然会go die。

不过,在不同的课上,疲劳值的变化量并不总是一样,就如在班主任的课上睡觉,疲劳值并不会下降太多,因为那样会睡得很不安心。

LYM是一个死要面子的人,他宁可冒着生命危险,也要挽回自己在老师心中的形象,因此他不能总是在人家的课上睡觉。他给自己定下了一个规矩:决不连续地在同一主科的课上睡觉,即如果LYM在主科X的某堂课上睡了觉,那么在下一堂(不一定是相邻的)主科X的课上,LYM就绝不会睡觉。

经过了这n节课后,LYM竟然没有死,LYM想知道自己对疲劳值的忍耐极限至少是多少。

输入格式

第一行,一个正整数n.

第二行,n个正整数,表示这n节课的课程安排。每个整数代表一门课程,科目代号对应关系参见下文的表格。(1~6号学科均为主科,7号学科不算作主科).

第三行,n个正整数,其中第i个数表示在第i节课上睡觉,疲劳值的减少量。

第四行,n个正整数,其中第i个数表示在第i节课上不睡觉,疲劳值的增加量。

第五行,一个整数,表示LYM的初始疲劳值。如果初始疲劳值大于了忍耐限度,LYM会在第一节课前就暴亡。

科目

语文

数学

英语

物理

化学

生物

其他

代号

1

2

3

4

5

6

7

输出格式

一个整数,表示LYM的忍耐限度的最小可能值

题解

二分忍耐度,状压dp验证

dp[i][j]表示表示前i节课上完后状态为j时的劳累度

动规方程见代码

代码

#include<stdio.h>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<queue>
#include<cstring>
#include<iostream>
using namespace std;
#define maxn 5002
#define inf 2e9
int a[maxn],b[maxn],c[maxn];
int n,m;
int dp[maxn][64];
bool check(int x)
{
int i,j;
for( i=0;i<=63;i++){dp[0][i]=m;}
for(i=1;i<=n;i++)
{
if(a[i]==7){
for(j=0;j<=63;j++)
{dp[i][j]=inf;
if(dp[i-1][j]<=x)dp[i][j]=dp[i-1][j]-b[i];}
}
else{
int k=1<<(a[i]-1);
for(j=0;j<=63;j++)
{
dp[i][j]=inf;
if(j&k)
{
if(dp[i-1][j^k]<=x) dp[i][j]=dp[i-1][j^k]-b[i];
}
else{
if(dp[i-1][j]<=x)
{
dp[i][j]=dp[i-1][j]+c[i];
}
if(dp[i-1][j^k]<=x){
dp[i][j]=min(dp[i][j],dp[i-1][j^k]+c[i]);
}
}
}
}
}
for(i=0;i<=63;i++) if(dp
[i]<=x) return true;
return false;
}
int main()
{
int i,j;
scanf("%d",&n);
for(i=1;i<=n;i++) scanf("%d",&a[i]);
for(i=1;i<=n;i++) scanf("%d",&b[i]);
for(i=1;i<=n;i++) scanf("%d",&c[i]);
scanf("%d",&m);
int l=m,r=inf;
while(l<=r){
int mid=(l+r)>>1;
if(check(mid)) r=mid-1;
else l=mid+1;
}
for(i=l-2;;i++) if(check(i)) break;
cout<<i;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: