EZOJ #226

传送门

分析

我们可以建一个k层图,把dp转移的三维对应到每个点上,每个第k层点连向0层点

我们让第0层点为实点其余为虚点,只要碰到虚点就dfs到他连得所有实点再将实点入队即可

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cctype>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<ctime>
#include<vector>
#include<set>
#include<map>
#include<stack>
using namespace std;
priority_queue<pair<int,int> >q;
bool vis[20][20][140000];
int d[140000],v[140000],a[140000],b[140000],n,m,K,res;
inline void go(int x,int y,int z){
    if(vis[x][y][z])return;
    vis[x][y][z]=1;
    if(x==m){
      if(y==K&&z<n&&res+b[z]<d[z]){
          d[z]=res+b[z];
          q.push(make_pair(-d[z],z));
      }
    }else {
      go(x+1,y,z);
      if(y<K)go(x+1,y+1,z^(1<<x));
    }
}
int main(){
    int i,j,k;
    scanf("%d%d",&n,&K);
    while((1<<m)<n)m++;
    memset(d,0x3,sizeof(d));
    for(i=0;i<n;i++){
      scanf("%d",&v[i]);
      if(v[i]>=0)d[i]=v[i],q.push(make_pair(-d[i],i));
    }
    for(i=0;i<n;i++)scanf("%d",&a[i]);
    for(i=0;i<n;i++)scanf("%d",&b[i]);
    while(!q.empty()){
      int x=q.top().second,y=-q.top().first;
      cout<<y<<endl;
      q.pop();
      if(x<n){
          if(y>d[x])continue;
          q.push(make_pair(-y-a[x],x+n));
      }else {
          res=y;
          go(0,0,x-n);
      }
    }
    int Ans=0;
    for(i=0;i<n;i++)Ans^=d[i];
    cout<<Ans;
    return 0;
}
posted @ 2019-03-25 10:06  水题收割者  阅读(181)  评论(0编辑  收藏  举报