【BZOJ】1187: [HNOI2007]神奇游乐园

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1187


 

每个格子都具有权值,求任意一个回路使得路径上的权值和最大。

 

裸的插头DP,注意一下几点:

1.因为不一定要全部格子都要走过,所以可以空一格不走,前提这个状态是没有上插头和左插头的。

2.每个格子都应该可以作为起始状态(新建连通块)。

3.关于形成回路的状态显然不能再往下转移,同时如果这个的轮廓线上除了左插头和右插头之外没有插头了,可以算入答案。

 

QwQ...细节还是看代码吧。


  1 #include<iostream>
  2 #include<cstdio>
  3 #include<algorithm>
  4 #include<vector>
  5 #include<cstdlib>
  6 #include<cmath>
  7 #include<cstring>
  8 using namespace std;
  9 #define maxn 10010
 10 #define llg long long 
 11 #define sizee 57
 12 #define maxZT (1<<18)
 13 #define yyj(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
 14 llg n,m,now,size[2],zt[2][maxZT],ans,la,code[maxn],quan;
 15 llg v[2][maxZT];
 16 
 17 struct node
 18 {
 19     llg x,val,pos;
 20 };
 21 
 22 vector<node>a[2][sizee];
 23 
 24 void outcode(llg x) {for (llg i=0;i<=m;i++) code[i]=x&3,x>>=2;}
 25 
 26 void encode(llg p,llg val)
 27 {
 28     llg x=0;
 29     for (llg i=0;i<=m;i++) x+=code[i]*(1<<(i*2));
 30     llg wz=x%sizee,E=a[p][wz].size();
 31     for (llg i=0;i<E;i++)
 32         if (a[p][wz][i].x==x)
 33         {
 34             a[p][wz][i].val=max(a[p][wz][i].val,val);
 35             v[p][a[p][wz][i].pos]=max(v[p][a[p][wz][i].pos],val);
 36             return ;
 37         }
 38     size[p]++;
 39     node NEW; NEW.x=x; NEW.val=val; NEW.pos=size[p];
 40     a[p][wz].push_back(NEW);
 41     zt[p][size[p]]=x; v[p][size[p]]=val;
 42 }
 43 
 44 void init_a(llg p){for (llg i=0;i<sizee;i++) a[p][i].clear(); size[p]=0;}
 45 
 46 void DP()
 47 {
 48     llg now=0;
 49     encode(0,0);
 50     for (llg i=1;i<=n;i++)
 51     {
 52         for (llg k=1;k<=size[now];k++) zt[now][k]*=4;
 53         for (llg j=1;j<=m;j++)
 54         {
 55             scanf("%lld",&quan);
 56             now^=1; la=now^1; size[now]=0; 
 57             init_a(now);
 58             for (llg k=1;k<=size[la];k++)
 59             {
 60                 outcode(zt[la][k]);
 61                 llg le=code[j-1],up=code[j],V=v[la][k];
 62                 
 63                 if (!le && !up) //空格
 64                 {
 65                     encode(now,V);
 66                 }
 67 //-------------------------------------------------------------------------------------
 68                 if (!le && !up)//没有插头,新建连通分量
 69                 {
 70                     if (j<m)
 71                     {
 72                         code[j-1]=1,code[j]=2;
 73                         encode(now,V+quan);
 74                     }
 75                     continue;
 76                 }
 77 //-------------------------------------------------------------------------------------
 78                 if (!le && up)//延续上插头
 79                 {
 80                     if (j<m) encode(now,V+quan);
 81                     code[j-1]=code[j]; code[j]=0;
 82                     encode(now,V+quan);
 83                     continue;
 84                 }
 85 //-------------------------------------------------------------------------------------
 86                 if (le && !up)//延续左插头
 87                 {
 88                     encode(now,V+quan);
 89                     if (j<m) 
 90                     {
 91                         code[j]=code[j-1]; code[j-1]=0;
 92                         encode(now,V+quan);
 93                     }
 94                     continue;
 95                 }
 96 //-------------------------------------------------------------------------------------
 97                 if (le==1 && up==2)//回路闭合,统计答案
 98                 {
 99                     bool pd=true;
100                     for (llg e=0;e<j-1;e++) if (code[e]) pd=false;
101                     for (llg e=j+1;e<=m;e++) if (code[e]) pd=false;
102                     if (pd) ans=max(ans,V+quan);
103                     //        if (pd) cout<<i<<" "<<j<<"--->"<<V+quan<<endl;
104                     continue;
105                 }
106 //-------------------------------------------------------------------------------------
107                 if (le==2 && up==1)//左插头为右括号,上插头为左括号,直接合并
108                 {
109                     code[j]=code[j-1]=0;
110                     encode(now,V+quan);
111                     continue;
112                 }
113 //-------------------------------------------------------------------------------------
114                 if (le==1 && up==1)//上左插头均为左括号,找到上插头所对应的右括号并将其修改为左括号
115                 {
116                     for (llg e=j+1;e<=m;e++) 
117                         if (code[e]==2)
118                         {
119                             code[e]=1;
120                             break;
121                         } 
122                     code[j]=code[j-1]=0;
123                     encode(now,V+quan);
124                     continue;
125                 }
126 //-------------------------------------------------------------------------------------
127                 if (le==2 && up==2)//上左插头均为右括号,找到左插头对应的左括号并将其修改为右括号
128                 {
129                     for (llg e=j-2;e>=0;e--)
130                         if (code[e]==1)
131                         {
132                             code[e]=2;
133                             break;
134                         }
135                     code[j]=code[j-1]=0;
136                     encode(now,V+quan);
137                     continue;
138                 }
139             }
140         }
141     }
142 }
143 
144 int main()
145 {
146     yyj("a");
147     ans=-1*0x7fffffff;
148     cin>>n>>m;
149     DP();
150     cout<<ans;
151     return 0;
152 }

 

posted @ 2017-02-21 21:40  №〓→龙光←  阅读(328)  评论(0编辑  收藏  举报