【BZOJ1226】[SDOI2009]学校食堂Dining

Description

小F 的学校在城市的一个偏僻角落,所有学生都只好在学校吃饭。学校有一个食堂,虽然简陋,但食堂大厨总能做出让同学们满意的菜肴。当然,不同的人口味也不一定相同,但每个人的口味都可以用一个非负整数表示。由于人手不够,食堂每次只能为一个人做菜。做每道菜所需的时间是和前一道菜有关的,若前一道菜的对应的口味是a,这一道为b,则做这道菜所需的时间为(a or b)-(a and b),而做第一道菜是不需要计算时间的。其中,or 和and 表示整数逐位或运算及逐位与运算,C语言中对应的运算符为“|”和“&”。学生数目相对于这个学校还是比较多的,吃饭做菜往往就会花去不少时间。因此,学校食堂偶尔会不按照大家的排队顺序做菜,以缩短总的进餐时间。虽然同学们能够理解学校食堂的这种做法,不过每个同学还是有一定容忍度的。也就是说,队伍中的第i 个同学,最多允许紧跟他身后的Bi 个人先拿到饭菜。一旦在此之后的任意同学比当前同学先拿到饭,当前同学将会十分愤怒。因此,食堂做菜还得照顾到同学们的情绪。现在,小F 想知道在满足所有人的容忍度这一前提下,自己的学校食堂做完这些菜最少需要多少时间。

Input

第一行包含一个正整数C,表示测试点的数据组数。每组数据的第一行包含一个正整数N,表示同学数。每组数据的第二行起共N行,每行包含两个用空格分隔的非负整数Ti和Bi,表示按队伍顺序从前往后的每个同学所需的菜的口味和这个同学的忍受度。每组数据之间没有多余空行。

Output

包含C行,每行一个整数,表示对应数据中食堂完成所有菜所需的最少时间。

Sample Input

2
5
5 2
4 1
12 0
3 3
2 2
2
5 0
4 0

Sample Output

16
1

HINT

对于第一组数据:同学1允许同学2或同学3在他之前拿到菜;同学2允许同学3在他之前拿到菜;同学3比较小气,他必须比他后面的同学先拿菜…… 一种最优的方案是按同学3、同学2、同学1、同学4、同学5做菜,每道菜所需的时间分别是0、8、1、6及1。 【数据规模和约定】对于30%的数据,满足1 ≤ N ≤ 20。对于100%的数据,满足1 ≤ N ≤ 1,000,0 ≤ Ti ≤ 1,000,0 ≤ Bi ≤ 7,1 ≤ C ≤ 5。存在30%的数据,满足0 ≤ Bi ≤ 1。存在65%的数据,满足0 ≤ Bi ≤ 5。存在45%的数据,满足0 ≤ Ti ≤ 130。

题解:由于Bi<=7,考虑状压。用f[i][j][k]表示前i个人都已经拿完菜了,第i个人后面的7个人的拿菜情况是j,最后一个拿菜的人是i+k(-7<=k<=7)的最小时间。然后转移即可。为了防止重复,有几点注意事项。

如果此时第i+1个人已经拿完菜了(即j&1),那么只能从f[i][j][k]转移到f[i+1][j>>1][k-1];否则,只能从f[i][..][..]只能转移到f[i][..][..]。

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
int n,ans; int f[1010][260][17],cnt[260],T[1010],B[1010];
inline int rd()
{
int ret=0,f=1; char gc=getchar();
while(gc<'0'||gc>'9') {if(gc=='-')f=-f; gc=getchar();}
while(gc>='0'&&gc<='9') ret=ret*10+gc-'0',gc=getchar();
return ret*f;
}
int calc(int a,int b)
{
if(a<=0) return 0;
return T[a]^T[b];
}
void work()
{
memset(f,0x3f,sizeof(f));
n=rd();
int i,j,k,l;
for(i=1;i<=n;i++) T[i]=rd(),B[i]=min(rd(),n-i);
f[0][0][8]=0;
for(i=0;i<n;i++) for(j=0;j<(1<<min(n-i,8));j++) for(k=max(8-i,0);k<=min(n-i,8)+8;k++)
{
if(j&1)
{
f[i+1][j>>1][k-1]=min(f[i+1][j>>1][k-1],f[i][j][k]);
continue;
}
int lim=min(n-i,8);
for(l=1;l<=lim;l++) if(!(j&(1<<(l-1))))
{
f[i][j|(1<<(l-1))][l+8]=min(f[i][j|(1<<(l-1))][l+8],f[i][j][k]+calc(i+k-8,i+l));
lim=min(lim,l+B[i+l]);
}
}
ans=1<<30;
for(i=max(8-n,0);i<=8;i++) ans=min(ans,f[n][0][i]);
printf("%d\n",ans);
}
int main()
{
int T=rd();
while(T--) work();
return 0;
}//1 2 5 0 4 0

最新文章

  1. .NET面试题系列[2] - .NET框架基础知识(2)
  2. SQL Server数据库SP命令祥解
  3. spring mvc定时任务的简单使用
  4. /proc/cpuinfo zz
  5. Scrum Meeting---Two(2015-10-26)
  6. 百度 WebUploader 简单入门示例
  7. windows 系统中打开一个数字证书所经历的过程
  8. HIbernate学习笔记(一) 了解hibernate并搭建环境建立第一个hello world程序
  9. php学习小技巧
  10. jquery中eq和get的区别与使用方法
  11. UVa 10491 Cows and Cars (概率&amp;广义三门问题 )
  12. 推荐两个针对github的chrome插件
  13. 创建 .gitignore 文件过滤规
  14. oracle报表功能
  15. hive删除表和表中的数据
  16. linux/shell/bash 自动输入密码或文本
  17. 【XSY1162】鬼计之夜 最短路
  18. SQLmap超详细文档和实例演示
  19. (整理)在REHL6.5上部署ASP.NET MVC
  20. codeforces724G Xor-matic Number of the Graph

热门文章

  1. C语言中不同类型的数据转换规则
  2. Spring IoC Container and Spring Bean Example Tutorial
  3. 使用websocket进行消息推送服务
  4. Yum编译安装Error Downloading Packages报错
  5. 2017.7.21 Linux中ELK服务后台运行方式
  6. 解决https协议服务器内部无法跳转的问题
  7. 通过项目了解JAVA注解
  8. 网页计算器 &amp;&amp; 简易网页时钟 &amp;&amp; 倒计时时钟
  9. 使用PostMan快速生成代码
  10. C#IAsyncResult异步回调函数的解释