题目描述:
QAQ…
题目分析:
状压DP…
观察到一个人的忍耐程度很小,可以状压…
f[i][j][k]表示[1 – i-1] 吃完了 i 之后 状态 j 中 为 1的人也吃饭了,且最后一个吃饭的人为 i+k 的最小代价
k可以为负数
转移的时候枚举 j
如果j&1不为0,那么证明i这个人吃饭了 可以转移到 f[i+1][j>>1][k-1] 去
如果为 0 那么证明 i 没吃饭 那么就枚举下一个吃饭的 转移到 f[i][j+(1<
题目链接:
Ac 代码:
#include <cstring>
#include <algorithm>
#include <cstdio>
#define f(i,j,k) dp[i][j][k+8]
#define inf 0x3f3f3f3f
#define int long long
int dp[1101][1<<9][20];
int t[1101],b[1101];
int n;
inline int cal(int x,int y){return x==0?0:t[x]^t[y];}
inline void work()
{
scanf("%lld",&n);
for(int i=1;i<=n;i++) scanf("%lld%lld",&t[i],&b[i]);
memset(dp,inf,sizeof(dp));
f(1,0,-1)=0;
for(int i=1;i<=n;i++)
for(int j=0;j<1<<8;j++)
for(int k=-8;k<=7;k++)
if(f(i,j,k)<inf)
{
if(j&1) f(i+1,j>>1,k-1)=std::min(f(i+1,j>>1,k-1),f(i,j,k));
else
{
int minx=inf;
for(int l=0;l<=7&&i+l<=minx;l++)
if(!(j&(1<<l)))
{
minx=std::min(minx,i+l+b[i+l]);
f(i,j+(1<<l),l)=std::min(f(i,j+(1<<l),l),f(i,j,k)+cal(i+k,i+l));
}
}
}
int ans=inf;
for(int i=-8;i<=7;i++) ans=std::min(ans,f(n+1,0,i));
printf("%lld\n",ans);
}
signed main()
{
int t;
scanf("%lld",&t);
while(t--) work();
return 0;
}