您的位置:首页 > 其它

BZOJ1226 SDOI2009学校食堂

2018-01-29 09:08 162 查看

这题状压DP太神了。

g[i][j][k]表示前i-1个人都已打到饭,自己和后七个人打饭的情况是j,当前最后一个打饭的与i的关系是k

如果j&1==1说明当前这个人也打了饭,那么可以转移到g[i+1][j>>1][k-1]因为i+1+k-1==i+k

然后我们再枚举当前哪个人要打饭计算状态即可。

学习了hzwer的代码

#include<bits/stdc++.h>
#define f(a,b,c) (g[a][b][c+8])
using namespace std;
int g[1005][256][16],ins[1005],tas[1005],n,T;
int calc(int x,int y)
{
if(!x)return 0;
return tas[x]^tas[y];
}
int main()
{
scanf("%d",&T);
while(T--)
{
memset(g,0x3f,sizeof(g));
f(1,0,-1)=0;scanf("%d",&n);
for(int i=1;i<=n;++i)scanf("%d%d",&tas[i],&ins[i]);
for(int i=1;i<=n;++i)
for(int j=0;j<(1<<8);++j)
for(int k=-8;k<=7;++k)
if(j&1)
{
f(i+1,j>>1,k-1)=min(f(i+1,j>>1,k-1),f(i,j,k));
}
else
{
int r=1e9;
for(int p=0;p<=7;++p)
if((j&(1<<p))==0)
{
if(i+p>r)break;
r=min(r,i+p+ins[i+p]);
f(i,j|(1<<p),p)=min(f(i,j|(1<<p),p),f(i,j,k)+calc(i+k,i+p));
}
}
int ans=1e9;
for(int k=-8;k<=-1;++k)
ans=min(ans,f(n+1,0,k));
printf("%d\n",ans);
}
return 0;
}

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: