版权声明:我这种蒟蒻的文章,真正的大佬一般看不上的_(:з」∠)_ https://blog.csdn.net/Paulliant/article/details/83627684
题意
https://www.luogu.org/problemnew/show/P2157
思路
不仅状压难想到,暴力分也极不和善。首先
的值不超过
,应该条件反射的想到状压
,不妨设
表示区间
内的同学结束用餐,
区间内的同学用餐情况为
,其中最后一个吃饭的同学是
其中
,转移就比较显然了。
前式表示
的移动,后式表示有多了一个吃饭的人,按照式子计算。
另外
数组出现负数时,
是个不错的选择。
代码
#include<bits/stdc++.h>
#define FOR(i,x,y) for(int i=(x),i##END=(y);i<=i##END;++i)
#define DOR(i,x,y) for(int i=(x),i##END=(y);i>=i##END;--i)
typedef long long LL;
using namespace std;
template<typename T>bool chk_max(T &x,T y){return x<y?x=y,1:0;}
template<typename T>bool chk_min(T &x,T y){return y<x?x=y,1:0;}
const int N=1003;
int T[N],B[N],dp[N][(1<<8)+3][20],n;
#define dp(x,y,z) dp[x][y][(z)+8]
int Cost(int x,int y)
{
if(x==0||y==n+1)return 0;
else return T[x]^T[y];
}
int main()
{
int C;
scanf("%d",&C);
while(C--)
{
int ans=2e9;
scanf("%d",&n);
FOR(i,1,n)scanf("%d%d",&T[i],&B[i]);
memset(dp,0x3f,sizeof(dp));
dp(1,0,-1)=0;
FOR(i,1,n)FOR(j,0,(1<<8)-1)FOR(k,-8,7)if(dp(i,j,k)<1e9)
{
if(j&1){chk_min(dp(i+1,j>>1,k-1),dp(i,j,k));continue;}
int maxer=1e9;
FOR(l,0,7)if(~j&(1<<l))
{
if(i+l>maxer)break;
chk_min(maxer,i+l+B[i+l]);
chk_min(dp(i,j|(1<<l),l),dp(i,j,k)+Cost(i+k,i+l));
}
}
FOR(i,-8,-1)chk_min(ans,dp(n+1,0,i));
printf("%d\n",ans);
}
return 0;
}