• 【Ural】【1519】Formula 1


    插头DP


    本题为CDQ《基于连通性状态压缩的动态规划的……(我忘了)》里的例题!(嗯就是这样……)

    先膜拜一下ccy大神……http://blog.sina.com.cn/s/blog_51cea4040100gmky.html

     

    在这里将我当初看插头DP的一些不解之处写出来,给大家提供一些参考:

      以前我老是搞不懂“左/右插头”的区分……今天终于搞明白了:左插头是一个联通块与轮廓线的左边的交点,右插头是靠右的交点……这下那些分情况讨论的状态转移瞬间就明白了= =

      然后是状态表示……其实以前用状压都是一位表示一个状态,而插头DP由于用的是3(4)进制,所以是二进制下的两位来表示一个插头的状态(两位的话就可以表示0/1/2了,一位只能表示0/1)

      状态转移其实就是删掉/加上插头的操作……看了代码很好懂……sigh……当年是一看长代码就头晕,唉

      其实我们是在对每一个格子枚举可行状态的……要不然怎么叫统计方案数啊= =(这一点我一开始真的没想到……so sad……too naive)

      其实在看插头DP代码的过程中也顺便理解了Hash……原来hash向后排是这个意思,开个数组记录下每个hash值所对应的原值就好了,好像也没那么难的样子……为什么当初我NOIP的时候就没学会呢……

      1 //Ural 1519
      2 #include<cmath>
      3 #include<vector>
      4 #include<cstdio>
      5 #include<cstring>
      6 #include<cstdlib>
      7 #include<iostream>
      8 #include<algorithm>
      9 #define rep(i,n) for(int i=0;i<n;++i)
     10 #define F(i,j,n) for(int i=j;i<=n;++i)
     11 #define D(i,j,n) for(int i=j;i>=n;--i)
     12 #define CC(a,b) memset(a,b,sizeof(a))
     13 #define pb push_back
     14 using namespace std;
     15 int getint(){
     16     int v=0,sign=1; char ch=getchar();
     17     while(ch<'0'||ch>'9'){ if (ch=='-') sign=-1; ch=getchar();}
     18     while(ch>='0'&&ch<='9'){ v=v*10+ch-'0'; ch=getchar();}
     19     return v*=sign;
     20 }
     21 const int N=1e7+10;
     22 typedef long long LL;
     23 typedef unsigned long long u64;
     24 /******************tamplate*********************/
     25 const int sz=199917;
     26 bool mp[15][15];
     27 int n,m,nn,mm,k;
     28 int tot[2],bit[15],hash[sz],state[2][sz];
     29 u64 dp[2][sz],ans;
     30 void init(){
     31     CC(mp,0);
     32     CC(dp,0);
     33     tot[0]=dp[0][1]=1,ans=k=0;
     34     state[0][1]=0;
     35     char ch;
     36     F(i,1,n){
     37         scanf("%c",&ch);
     38         F(j,1,m){
     39             scanf("%c",&ch);
     40             mp[i][j]=ch=='.';
     41             if (mp[i][j]) nn=i,mm=j;
     42         }
     43     }
     44 }
     45 void hash_in(int s,u64 sum){
     46     int p=s%sz;
     47     while(hash[p]){
     48         if (state[k][hash[p]]==s){
     49             dp[k][hash[p]]+=sum;
     50             return;
     51         }
     52         p++;
     53         if (p==sz) p=0;
     54     }
     55     hash[p]=++tot[k];
     56     state[k][hash[p]]=s;
     57     dp[k][hash[p]]=sum;
     58 }
     59 #define in hash_in(s,sum)
     60 void work(){
     61     F(i,1,n){
     62         F(j,1,m){
     63             k^=1;
     64             tot[k]=0;
     65             CC(hash,0);
     66             F(u,1,tot[1-k]){
     67                 int s=state[1-k][u];
     68                 u64 sum=dp[1-k][u];
     69                 int p=(s>>bit[j-1])&3,q=(s>>bit[j])&3;
     70                 if (!mp[i][j]){ if(!p && !q) in; }
     71                 else{
     72                     if (!p && !q){
     73                         if (!mp[i][j+1]||!mp[i+1][j]) continue;
     74                         s=s^(1<<bit[j-1])^(1<<bit[j]<<1),in;
     75                     }else if(!p && q){
     76                         if (mp[i][j+1]) in;
     77                         if (mp[i+1][j]) s=s^q*(1<<bit[j-1])^q*(1<<bit[j]),in;
     78                     }else if(p && !q){
     79                         if (mp[i+1][j]) in;
     80                         if (mp[i][j+1]) s=s^p*(1<<bit[j-1])^p*(1<<bit[j]),in;
     81                     }else if(p+q==2){
     82                         int nd=1;
     83                         F(u,j+1,m){
     84                             int w=(s>>bit[u])&3;
     85                             if (w==1) nd++;
     86                             if (w==2) nd--;
     87                             if (!nd) {s-=(1<<bit[u]); break;}//这两个地方不能将+/-改成^
     88                             //废话!因为这里是把右插头(2)改成左插头(1)了!用异或就把2改成3了……那算神马……
     89                         }
     90                         s=s^(1<<bit[j])^(1<<bit[j-1]),in;
     91                     }else if(p+q==4){
     92                         int nd=1;
     93                         D(u,j-2,1){
     94                             int w=(s>>bit[u])&3;
     95                             if (w==2) nd++;
     96                             if (w==1) nd--;
     97                             if (!nd) {s+=(1<<bit[u]); break;}//这里是将左插头(1)改成右插头(2)
     98                         }
     99                         s=s^(1<<bit[j]<<1)^(1<<bit[j-1]<<1),in;
    100                     }else if(p==1 && q==2){
    101                         if (i==nn && j==mm) ans+=sum;
    102                     }else if(p==2 && q==1) s=s^(1<<bit[j-1]<<1)^(1<<bit[j]),in;
    103                 }
    104             }
    105         }
    106         F(j,1,tot[k]) state[k][j]<<=2;
    107     }
    108     printf("%llu
    ",ans);
    109 }
    110 
    111 int main(){
    112 #ifndef ONLINE_JUDGE
    113     freopen("1519.in","r",stdin);
    114     freopen("1519.out","w",stdout);
    115 #endif
    116     F(i,0,13) bit[i]=i<<1;
    117     while(scanf("%d%d",&n,&m)!=EOF){
    118         init();
    119         work();
    120     }
    121     return 0;
    122 }
    View Code
  • 相关阅读:
    Docker学习重点(5)~Docker镜像原理、commit提交镜像
    Docker学习重点(6)~容器数据卷
    Linux安装RocketMQ
    4.1 打包和压缩的概念和区别
    4.3 Linux压缩文件或目录为.zip格式(zip命令)
    3.21 Linux PATH环境变量及作用(初学者必读)
    4.6 Linux解压.gz格式的文件(gunzip命令)
    4.4 Linux解压.zip格式的文件(unzip命令)
    3.18 Linux懒人神器:命令自动补全功能!
    4.5 Linux压缩文件或目录中文件为.gz格式(gzip命令)
  • 原文地址:https://www.cnblogs.com/Tunix/p/4312203.html
Copyright © 2020-2023  润新知