一揽子计划

liaoliao的BZOJ题表,一题题做。。

                  完成量(1/139)

BZOJ1226: [SDOI2009]学校食堂Dining

  因为每个人的B值不超过7,所以上一个吃饭的人应该在这个人前面不超过7,后面也不超过7的位置上

  状压DP,设f[i][j][k]为前i-1个人都已经吃完饭了,第i到i+7个人的状态为j,最后一个吃饭的人为第i+k个人

  然后就可以转移

  对于j&1==1,就是说第i个人已经吃了饭了,那么f[i+1][j>>1][k-1]=f[i][j][k],两者的意义是一样的

  对于j&1==0,那么就枚举应当作为最后一个吃饭的人的位置i+p,f[i][j^(1<<p)][p]=f[i][j][k]+cal(i+k,i+p))

  然后因为k有可能为负,所以整体的k+8存入数组

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
int T[1100],B[1100];
int f[1100][310][21];
int cal(int x,int y){return (x==0||y==0)?0:T[x]^T[y];}
int main()
{
    int cas;
    scanf("%d",&cas);
    while(cas--)
    {
        int n;
        scanf("%d",&n);
        for(int i=1;i<=n;i++) scanf("%d%d",&T[i],&B[i]);
        memset(f,63,sizeof(f));
        f[1][0][7]=0;
        for(int i=1;i<=n;i++)
        {
            for(int j=0;j<(1<<8);j++)
            {
                for(int k=0;k<=15;k++)
                {
                    if(f[i][j][k]==f[0][0][0]) continue;
                    if(j&1) f[i+1][j>>1][k-1]=min(f[i+1][j>>1][k-1],f[i][j][k]);
                    else
                    {
                        int mmax=1<<30;
                        for(int p=0;p<=7;p++)
                        {
                            if((j&(1<<p))==0)
                            {
                                if(i+p>mmax) break;
                                mmax=min(mmax,i+p+B[i+p]);
                                f[i][j^(1<<p)][p+8]=min(f[i][j^(1<<p)][p+8],f[i][j][k]+cal(i+k-8,i+p));
                            }
                        }
                    }
                }
            }
        }
        int ans=1<<30;
        for(int k=0;k<=8;k++) ans=min(f[n+1][0][k],ans);
        printf("%d\n",ans);
    }
    return 0;
}
BZOJ1226

BZOJ1560: [JSOI2009]火星藏宝图

猜你喜欢

转载自www.cnblogs.com/Never-mind/p/10323034.html