状压DP
然而我一开始没!有!想!粗!来!
只好参(chao)考(xi)神犇的思路。。
大致是酱的
f(i,j,k)
f
(
i
,
j
,
k
)
表示前
i−1
i
−
1
个人已经吃了饭,且在
i
i
之后的状态为的人也吃了饭(用二进制表示后面的状态),最后吃的那个人是
i
i
之后的第个
(注意
k
k
可以是负数)
然后
如果&
1=1
1
=
1
那么就表明第
i
i
个人也是吃了的,所以可以转移到
否则就枚举下一个吃饭的人,转移到
f(i,j+1<<l,l)
f
(
i
,
j
+
1
<<
l
,
l
)
这么看也不是很难吧哈。。
#include<cstdio>
#include<cstring>
#include<algorithm>
#define g getchar()
#define f(i,j,k) ge[i][j][k+8]
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
inline ll read(){
ll x=0,f=1;char ch=g;
for(;ch<'0'||ch>'9';ch=g)if(ch=='-')f=-1;
for(;ch>='0'&&ch<='9';ch=g)x=x*10+ch-'0';
return x*f;
}
inline void out(ll x){
int a[25],wei=0;
if(x<0)putchar('-'),x=-x;
for(;x;x/=10)a[++wei]=x%10;
if(wei==0){puts("0");return;}
for(int j=wei;j>=1;--j)putchar('0'+a[j]);
putchar('\n');
}
int t[1005],Q,ge[1005][257][17],n,b[1005],ans;
int clear(){memset(ge,inf,sizeof(ge));}
inline int sum(int x,int y){return x==0?0:t[x]^t[y];}
//这里说明一下,根据容斥原理,a|b-a&b=a^b,不信可以手算几个
int main(){
// freopen("","r",stdin);
// freopen("","w",stdout);
Q=read();
for(;Q--;){
clear();
n=read();
for(int i=1;i<=n;++i)t[i]=read(),b[i]=read();
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)=min(f(i+1,j>>1,k-1),f(i,j,k));
else{
int lim=inf;//lim是限制,就是防止超出了后面人的要求
for(int l=0;l<=7;++l)
if(!(j&(1<<l))){
if(i+l>lim)break;
lim=min(lim,i+l+b[i+l]);
f(i,j+(1<<l),l)=min(f(i,j+(1<<l),l),f(i,j,k)+sum(i+k,i+l));
}
}
}
ans=inf;
for(int i=-8;i<=7;++i)ans=min(ans,f(n+1,0,i));
out(ans);
}
return 0;
}