好学易懂 从零开始的插头DP(三)

写在前面

这篇文章主要是介绍一些括号表示法和简单回路的基本变化,下一篇会是一些非回路(最小表示),毒瘤状态(正wa着所以咕着),结合矩阵乘法加速等一些复杂应用。下下篇应该会是结尾,介绍一些除了路径问题以外的应用。这几篇题目的部分不会讲的非常详细,主要是自己思考,所以只会说大体思路。

FZU 1977(这个OJ要用I64d不能lld,不然wa)

题目大意:
n*m的格子,有些格子不能走,有些必须走,有些可以走。问,合法回路个数。
题目分析:
对于基本模板,有两个地方要处理。
一是插头转移,转移的时候不仅要考虑插头情况,还要考虑格点情况,这个题目格点情况有些变化。
二是终止格点不再确定。我的思路是最后一个必须走的点和它之后的可走的点都可以做终止格点,终止条件是只有一个左括号和右括号。
代码如下:

#include<stdio.h>
#include<iostream>
#include<cstring>
using namespace std;
const __int64 hs=10007;
__int64 n,m,ex,ey,now,last,ans;
__int64 a[13][13],b[13][13],head[100010],nex[100010],que[2][100010],val[2][100010],cnt[2],inc[13];
void init()
{scanf("%lld%lld",&n,&m);memset(a,0,sizeof(a));memset(b,0,sizeof(b));memset(head,0,sizeof(head)); memset(nex,0,sizeof(nex));   memset(que,0,sizeof(que));memset(val,0,sizeof(val));memset(cnt,0,sizeof(cnt));memset(inc,0,sizeof(inc)); ans=0;for (int i=1;i<=n;i++){for (int j=1;j<=m;j++){char ch=getchar();while (ch!='*'&&ch!='O'&&ch!='X') ch=getchar();if (ch=='X') a[i][j]=0;else if (ch=='*') a[i][j]=2;else {a[i][j]=1;ex=i;ey=j;}}}inc[0]=1;for(int i=1;i<=13;i++){inc[i]=inc[i-1]<<2;}for (int i=n;i>=1;i--){for (int j=m;j>=1;j--){if (a[i][j]!=0) b[i][j]=1;if (i==ex&&j==ey) return;}}
}
inline void insert(__int64 bit,__int64 num)
{__int64 u=bit%hs+1;for(int i=head[u];i;i=nex[i]){if(que[now][i]==bit){val[now][i]+=num;return;}}nex[++cnt[now]]=head[u];head[u]=cnt[now];que[now][cnt[now]]=bit;val[now][cnt[now]]=num;
}
inline void solve()
{cnt[now]=1; val[now][1]=1; que[now][1]=0;for(int i=1;i<=n;i++){for(int j=1;j<=cnt[now];j++){que[now][j]<<=2;}for(int j=1;j<=m;++j){memset(head,0,sizeof(head));last=now; now^=1;cnt[now]=0;for(int k=1;k<=cnt[last];++k){__int64 bit=que[last][k],num=val[last][k];__int64 b1=(bit>>((j-1)*2))%4,b2=(bit>>(j*2))%4;if(a[i][j]==0){if(!b1&&!b2) insert(bit,num);}else if(!b1&&!b2){if (a[i][j]==2) insert(bit,num);if(a[i+1][j]&&a[i][j+1]) insert(bit+inc[j-1]+inc[j]*2,num);}else if(!b1&&b2){if(a[i][j+1]) insert(bit,num);if(a[i+1][j]) insert(bit-inc[j]*b2+inc[j-1]*b2,num);}else if(b1&&!b2){if(a[i+1][j]) insert(bit,num);if(a[i][j+1]) insert(bit-inc[j-1]*b1+inc[j]*b1,num);}else if(b1==1&&b2==1){int flag=1;for(int l=j+1;l<=m;++l){if((bit>>(l*2))%4==1) flag++;if((bit>>(l*2))%4==2) flag--;if(!flag){insert(bit-inc[j]-inc[j-1]-inc[l],num);break;}}}else if(b1==2&&b2==2){int flag=1;for(int l=j-2;l>=0;--l){if((bit>>(l*2))%4==1) flag--;if((bit>>(l*2))%4==2) flag++;if(!flag){insert(bit-inc[j]*2-inc[j-1]*2+inc[l],num);break;}}}else if(b1==2&&b2==1) insert(bit-inc[j-1]*2-inc[j],num);else if (bit-inc[j-1]-inc[j]-inc[j]==0&&b[i][j]==1) ans=ans+num;}}}
}
int main()
{int t;scanf("%lld",&t);for (int i=1;i<=t;i++){init();solve();printf("Case %d: %I64d\n",i,ans);}return 0;
}

P3190 [HNOI2007]神奇游乐园

题目大意:
n*m的格子(n<=100,m<=6),每个格子有一个权值。求最大权回路的权值。
题目分析:
现在我们已经会处理可选格点了。这里全部都是可选格点。再加上一个很简单的变化,状态改为记录最大权。同时处理插头的时候判断要不要加上这个点的权值。
代码如下:

#include<cstdio>
#include<cstring>
using namespace std;
const long long hs=299987;
long long n,m,ex,ey,now,last,ans;
long long a[101][8],head[300000],next[2<<8],que[2][2<<8],val[2][2<<8],cnt[2],inc[10];
void init()
{scanf("%lld%lld",&n,&m);for (int i=1;i<=n;i++){for (int j=1;j<=m;j++){scanf("%lld",&a[i][j]);}}inc[0]=1;for(int i=1;i<=8;i++){inc[i]=inc[i-1]<<2;}ans=-(n*m*1001);
}
inline void insert(long long bit,long long num)
{long long u=bit%hs+1;for(int i=head[u];i;i=next[i]){if(que[now][i]==bit){if (val[now][i]<num) val[now][i]=num;return;}}next[++cnt[now]]=head[u];head[u]=cnt[now];que[now][cnt[now]]=bit;val[now][cnt[now]]=num;
}
inline void solve()
{cnt[now]=1; val[now][1]=0; que[now][1]=0;for(int i=1;i<=n;i++){for(int j=1;j<=cnt[now];j++){que[now][j]<<=2;}for(int j=1;j<=m;++j){memset(head,0,sizeof(head));last=now; now^=1;cnt[now]=0;for(int k=1;k<=cnt[last];++k){long long bit=que[last][k],num=val[last][k]+a[i][j];long long b1=(bit>>((j-1)*2))%4,b2=(bit>>(j*2))%4;if(!b1&&!b2){insert(bit,num-a[i][j]);if(i!=n&&j!=m) insert(bit+inc[j-1]+inc[j]*2,num);}else if(!b1&&b2){if(j!=m) insert(bit,num);if(i!=n) insert(bit-inc[j]*b2+inc[j-1]*b2,num);}else if(b1&&!b2){if(i!=n) insert(bit,num);if(j!=m) insert(bit-inc[j-1]*b1+inc[j]*b1,num);}else if(b1==1&&b2==1){int flag=1;for(int l=j+1;l<=m;++l){if((bit>>(l*2))%4==1) flag++;if((bit>>(l*2))%4==2) flag--;if(!flag){insert(bit-inc[j]-inc[j-1]-inc[l],num);break;}}}else if(b1==2&&b2==2){int flag=1;for(int l=j-2;l>=0;--l){if((bit>>(l*2))%4==1) flag--;if((bit>>(l*2))%4==2) flag++;if(!flag){insert(bit-inc[j]*2-inc[j-1]*2+inc[l],num);break;}}}else if(b1==2&&b2==1) insert(bit-inc[j-1]*2-inc[j],num);else if (num>ans) ans=num;}}}
}
int main()
{init();solve();printf("%lld\n",ans);return 0;
}

hdu 1964

题目大意:
每个相邻格子之间有一个墙,走过需要花费一定的代价,现在求经过所有点的闭合回路的最小代价。
题目分析:
通过上一题,我们学会了求最大值,最小值同理。这里的代价不在格点上在插头上,稍微转换下就行了。
代码如下:

#include<stdio.h>
#include<iostream>
#include<cstring>
#include<cmath>
#include<string>
using namespace std;
const long long hs=29987;
long long n,m,ex,ey,now,last,ans;
long long a[13][13],h[13][13],l[13][13],head[200000],nex[200000],que[2][200000],val[2][200000],cnt[2],inc[13];
void init()
{memset(a,0,sizeof(a));memset(h,0,sizeof(h));memset(l,0,sizeof(l));memset(head,0,sizeof(head)); memset(nex,0,sizeof(nex));   memset(que,0,sizeof(que));memset(val,0,sizeof(val));memset(cnt,0,sizeof(cnt));memset(inc,0,sizeof(inc)); string str;scanf("%lld%lld",&n,&m);for (int i=1;i<=n;i++){for (int j=1;j<=m;j++){a[i][j]=1;}}ex=n;ey=m;getline(cin,str);getline(cin,str);ans=0;for (int i=1;i<=n-1;i++){char ch=getchar();while (ch!='#') ch=getchar();for (int j=1;j<=m-1;j++){scanf("%d",&h[i][j]);ans=ans+abs(h[i][j]);}getline(cin,str);for (int j=1;j<=m;j++){ch=getchar();while (ch!='#') ch=getchar();scanf("%d",&l[i][j]);ans=ans+abs(l[i][j]);} getline(cin,str);}char ch=getchar();while (ch!='#') ch=getchar();for (int j=1;j<=m-1;j++){scanf("%d",&h[n][j]);ans=ans+abs(h[n][j]);}getline(cin,str);getline(cin,str); inc[0]=1;for(int i=1;i<=13;i++){inc[i]=inc[i-1]<<2;}
}
inline void insert(long long bit,long long num)
{long long u=bit%hs+1;for(int i=head[u];i;i=nex[i]){if(que[now][i]==bit){if (val[now][i]>num) val[now][i]=num;return;}}nex[++cnt[now]]=head[u];head[u]=cnt[now];que[now][cnt[now]]=bit;val[now][cnt[now]]=num;
}
inline void solve()
{cnt[now]=1; val[now][1]=0; que[now][1]=0;for(int i=1;i<=n;i++){for(int j=1;j<=cnt[now];j++){que[now][j]<<=2;}for(int j=1;j<=m;++j){memset(head,0,sizeof(head));last=now; now^=1;cnt[now]=0;for(int k=1;k<=cnt[last];++k){long long bit=que[last][k],num=val[last][k];long long b1=(bit>>((j-1)*2))%4,b2=(bit>>(j*2))%4;if (b1) num=num+h[i][j-1];if (b2) num=num+l[i-1][j];if(!b1&&!b2){if(a[i+1][j]&&a[i][j+1]) insert(bit+inc[j-1]+inc[j]*2,num);}else if(!b1&&b2){if(a[i][j+1]) insert(bit,num);if(a[i+1][j]) insert(bit-inc[j]*b2+inc[j-1]*b2,num);}else if(b1&&!b2){if(a[i+1][j]) insert(bit,num);if(a[i][j+1]) insert(bit-inc[j-1]*b1+inc[j]*b1,num);}else if(b1==1&&b2==1){int flag=1;for(int l=j+1;l<=m;++l){if((bit>>(l*2))%4==1) flag++;if((bit>>(l*2))%4==2) flag--;if(!flag){insert(bit-inc[j]-inc[j-1]-inc[l],num);break;}}}else if(b1==2&&b2==2){int flag=1;for(int l=j-2;l>=0;--l){if((bit>>(l*2))%4==1) flag--;if((bit>>(l*2))%4==2) flag++;if(!flag){insert(bit-inc[j]*2-inc[j-1]*2+inc[l],num);break;}}}else if(b1==2&&b2==1) insert(bit-inc[j-1]*2-inc[j],num);else if(i==ex&&j==ey) if (num<ans) ans=num;}}}
}
int main()
{int t;scanf("%d",&t);while (t--){init();solve();printf("%lld\n",ans);      }return 0;
}

poj 1739

题目大意:
有些格点必须走,有些不能走,问从左下角走到右下角多少种路径。
题目分析:
我们可以在最后加两行,第一行只有头尾可走,第二行全部可走,然后就转换为了回路问题。楼教主男人八题之一,不过记得调一下hash参数。1e5会tle,1e4就行了。
代码如下:

#include<stdio.h>
#include<iostream>
#include<cstring>
using namespace std;
const long long hs=29987;
long long n,m,ex,ey,now,last,ans;
long long a[13][13],head[300010],nex[300010],que[2][300010],val[2][300010],cnt[2],inc[13];
void init()
{ans=0;memset(a,0,sizeof(a));memset(head,0,sizeof(head));  memset(nex,0,sizeof(nex));   memset(que,0,sizeof(que));memset(val,0,sizeof(val));memset(cnt,0,sizeof(cnt));memset(inc,0,sizeof(inc)); scanf("%lld%lld",&n,&m);for (int i=1;i<=n;i++){for (int j=1;j<=m;j++){char ch=getchar();while (ch!='#'&&ch!='.') ch=getchar();if (ch!='.') a[i][j]=0;else {a[i][j]=1;}}}string str;a[n+1][1]=1;a[n+1][m]=1;for (int j=2;j<=m-1;j++){a[n+1][j]=0;}for (int j=1;j<=m;j++){a[n+2][j]=1;}n=n+2;ex=n;ey=m;inc[0]=1;for(int i=1;i<=13;i++){inc[i]=inc[i-1]<<2;}
}
inline void insert(long long bit,long long num)
{long long u=bit%hs+1;for(int i=head[u];i;i=nex[i]){if(que[now][i]==bit){val[now][i]+=num;return;}}nex[++cnt[now]]=head[u];head[u]=cnt[now];que[now][cnt[now]]=bit;val[now][cnt[now]]=num;
}
inline void solve()
{cnt[now]=1; val[now][1]=1; que[now][1]=0;for(int i=1;i<=n;i++){for(int j=1;j<=cnt[now];j++){que[now][j]<<=2;}for(int j=1;j<=m;++j){memset(head,0,sizeof(head));last=now; now^=1;cnt[now]=0;for(int k=1;k<=cnt[last];++k){long long bit=que[last][k],num=val[last][k];long long b1=(bit>>((j-1)*2))%4,b2=(bit>>(j*2))%4;if(!a[i][j]){if(!b1&&!b2) insert(bit,num);}else if(!b1&&!b2){if(a[i+1][j]&&a[i][j+1]) insert(bit+inc[j-1]+inc[j]*2,num);}else if(!b1&&b2){if(a[i][j+1]) insert(bit,num);if(a[i+1][j]) insert(bit-inc[j]*b2+inc[j-1]*b2,num);}else if(b1&&!b2){if(a[i+1][j]) insert(bit,num);if(a[i][j+1]) insert(bit-inc[j-1]*b1+inc[j]*b1,num);}else if(b1==1&&b2==1){int flag=1;for(int l=j+1;l<=m;++l){if((bit>>(l*2))%4==1) flag++;if((bit>>(l*2))%4==2) flag--;if(!flag){insert(bit-inc[j]-inc[j-1]-inc[l],num);break;}}}else if(b1==2&&b2==2){int flag=1;for(int l=j-2;l>=0;--l){if((bit>>(l*2))%4==1) flag--;if((bit>>(l*2))%4==2) flag++;if(!flag){insert(bit-inc[j]*2-inc[j-1]*2+inc[l],num);break;}}}else if(b1==2&&b2==1) insert(bit-inc[j-1]*2-inc[j],num);else if(i==ex&&j==ey) ans+=num;}}}
}
int main()
{while (1){init();if (n==2&&m==0) break;solve();printf("%lld\n",ans);}return 0;
}

hdu 4285

题目大意:
n*m的棋盘,有些格子不能走,有些必须走。问没有回路套回路且总共k条回路方案数。
题目分析:
这个题目调了一会儿哈希,mle了一会儿。最后把nex,head数组,longlong变int,qaq。
题目有两个变化,第一个是k条回路,好处理。压进状态里就行了。另一个是回路套回路,让某个回路合拢时,左侧括号时奇数个,则出现了回路套回路,因为总数为偶数,左侧为奇数则右侧也为奇数。每次合拢只能在一边消去2个,最后一定是回路套回路。这个题目最小表示时限勉强,括号匹配无压力。
代码如下:

/*
bit最高三位用来标记k
(m+1)个位用来标记插头
*/
#include<stdio.h>
#include<iostream>
#include<cstring>
using namespace std;
const long long hs=199987;
const long long mod=1e9+7;
long long n,m,ex,ey,now,last,ans,sk;
int a[15][15],head[800010],nex[800010],que[2][800010],cnt[2],inc[15];
long long val[2][800010];
void init()
{ans=0;memset(a,0,sizeof(a));memset(head,0,sizeof(head));  memset(nex,0,sizeof(nex));   memset(que,0,sizeof(que));memset(val,0,sizeof(val));memset(cnt,0,sizeof(cnt));memset(inc,0,sizeof(inc)); scanf("%lld%lld%lld",&n,&m,&sk);if (sk>36) sk=37; for (int i=1;i<=n;i++){for (int j=1;j<=m;j++){char ch=getchar();while (ch!='*'&&ch!='.') ch=getchar();if (ch!='.') a[i][j]=0;else {a[i][j]=1;ex=i;ey=j;}}}inc[0]=1;for(int i=1;i<=14;i++){inc[i]=inc[i-1]<<2;}
}
inline void insert(long long bit,long long num)
{long long u=bit%hs+1;for(int i=head[u];i;i=nex[i]){if(que[now][i]==bit){val[now][i]=(val[now][i]+num)%mod;return;}}nex[++cnt[now]]=head[u];head[u]=cnt[now];que[now][cnt[now]]=bit;val[now][cnt[now]]=num;
}
inline void solve()
{cnt[now]=1; val[now][1]=1; que[now][1]=0;for(int i=1;i<=n;i++){for(int j=1;j<=cnt[now];j++){long long t=que[now][j]/inc[m+1];que[now][j]=((que[now][j]-t*inc[m+1])<<2)+t*inc[m+1];}for(int j=1;j<=m;++j){memset(head,0,sizeof(head));last=now; now^=1;cnt[now]=0;
//          cout<<i<<" "<<j<<"   :"<<endl;
//          cout<<"--------------"<<endl; for(int k=1;k<=cnt[last];++k){long long bit=que[last][k],num=val[last][k];long long b1=(bit>>((j-1)*2))%4,b2=(bit>>(j*2))%4,t=bit/inc[m+1];
//                  cout<<bit<<endl;
//                  cout<<b1<<" "<<b2<<" "<<t<<endl;
//                  cout<<"-----------------"<<endl;if(!a[i][j]){if(!b1&&!b2) insert(bit,num);}else if(!b1&&!b2){if(a[i+1][j]&&a[i][j+1]) insert(bit+inc[j-1]+inc[j]*2,num);}else if(!b1&&b2){if(a[i][j+1]) insert(bit,num);if(a[i+1][j]) insert(bit-inc[j]*b2+inc[j-1]*b2,num);}else if(b1&&!b2){if(a[i+1][j]) insert(bit,num);if(a[i][j+1]) insert(bit-inc[j-1]*b1+inc[j]*b1,num);}else if(b1==1&&b2==1){int flag=1;for(int l=j+1;l<=m;++l){if((bit>>(l*2))%4==1) flag++;if((bit>>(l*2))%4==2) flag--;if(!flag){insert(bit-inc[j]-inc[j-1]-inc[l],num);break;}}}else if(b1==2&&b2==2){int flag=1;for(int l=j-2;l>=0;--l){if((bit>>(l*2))%4==1) flag--;if((bit>>(l*2))%4==2) flag++;if(!flag){insert(bit-inc[j]*2-inc[j-1]*2+inc[l],num);break;}}}else if(b1==2&&b2==1) insert(bit-inc[j-1]*2-inc[j],num);else{int flag=0;for (int jj=0;jj<=j-2;jj++){if ((bit>>((jj)*2))%4!=0) flag=1-flag;}if (flag) continue;if (t==sk-1&&i==ex&&j==ey) ans=(ans+num)%mod;else insert(bit-inc[j-1]-inc[j]*2+inc[m+1],num);}}}}
}
int main()
{int t;scanf("%d",&t); while(t--){init();solve();printf("%lld\n",ans);}return 0;
}

hdu 6875

题目大意:
一个n*n的棋盘,每个格子有个权值,让你染黑一些两两不相邻格子使得黑格权值和最大且剩下的格子可以组成一个回路。
题目分析:
黑色权值最大就是白色回路权值和最小。
至于染色问题,意外的好处理,因为黑色格子没有插头,其实就是原来的0状态要分成黑白两种,正好原来只有左右括号(1,2)和白0,用的4进制,剩下来的3分给黑0。转移稍微多加了几个分类讨论。需要注意的是,因为黑色不连续,终止格点即最后白格可以是最后一个,或者倒数第二个。
另:这题30组,不能无脑memset,否则tle。要用mark数组标记哈希表来清零用过的。
代码如下:

/*
bit 0 无插头为白格
bit 1 左括号
bit 2 右括号
bit 3 黑格
*/
#include<stdio.h>
#include<iostream>
#include<cstring>
using namespace std;
const long long hs=299987;
long long n,m,ex,ey,now,last,ans,sum,s;
long long a[13][13],b[13][13],head[300010],nex[300010],mark[300010];
long long que[2][300010],val[2][300010],cnt[2],inc[14];
void init()
{memset(a,0,sizeof(a));memset(b,0,sizeof(b));sum=0;ans=1e9+7;scanf("%lld",&n);for (int i=1;i<=n;i++){for (int j=1;j<=n;j++){scanf("%lld",&b[i][j]); sum=sum+b[i][j];a[i][j]=1;}}inc[0]=1;for(int i=1;i<=13;i++){inc[i]=inc[i-1]<<2;}
}
inline void insert(long long bit,long long num)
{long long u=bit%hs+1;if (mark[u]!=s) {head[u]=0;mark[u]=s;}for(int i=head[u];i;i=nex[i]){if(que[now][i]==bit){if (val[now][i]>num) val[now][i]=num;return;}}nex[++cnt[now]]=head[u];head[u]=cnt[now];que[now][cnt[now]]=bit;val[now][cnt[now]]=num;
}
inline void solve()
{cnt[now]=1; val[now][1]=0; que[now][1]=0;for(int i=1;i<=n;i++){for(int j=1;j<=cnt[now];j++){que[now][j]<<=2;}for(int j=1;j<=n;++j){s++;last=now; now^=1;cnt[now]=0;for(int k=1;k<=cnt[last];++k){long long bit=que[last][k],num=val[last][k]+b[i][j];long long b1=(bit>>((j-1)*2))%4,b2=(bit>>(j*2))%4;if (b1==3&&b2==3){if(a[i+1][j]&&a[i][j+1]) insert(bit-inc[j-1]*2-inc[j],num);}else if (b1==3&&b2==0){if(a[i+1][j]&&a[i][j+1]) insert(bit-inc[j-1]*3+inc[j-1]+inc[j]*2,num);}else if (b1==3){if(a[i][j+1]) insert(bit-inc[j-1]*3,num);if(a[i+1][j]) insert(bit-inc[j-1]*3-inc[j]*b2+inc[j-1]*b2,num);}else if (b2==3&&b1==0){if(a[i+1][j]&&a[i][j+1]) insert(bit-inc[j]*3+inc[j-1]+inc[j]*2,num);}else if (b2==3){if(a[i+1][j]) insert(bit-inc[j]*3,num);if(a[i][j+1]) insert(bit-inc[j]*3-inc[j-1]*b1+inc[j]*b1,num);}  else if(!b1&&!b2){//if (i==n&&j==n&&num-b[i][j]<ans) ans=num-b[i][j];long long newbit=bit;if (a[i][j+1]) newbit=newbit+inc[j]*3;if (a[i+1][j]) newbit=newbit+inc[j-1]*3;insert(newbit,num-b[i][j]);if(a[i+1][j]&&a[i][j+1]) insert(bit+inc[j-1]+inc[j]*2,num);}else if(!b1&&b2){if(a[i][j+1]) insert(bit,num);if(a[i+1][j]) insert(bit-inc[j]*b2+inc[j-1]*b2,num);}else if(b1&&!b2){if(a[i+1][j]) insert(bit,num);if(a[i][j+1]) insert(bit-inc[j-1]*b1+inc[j]*b1,num);}else if(b1==1&&b2==1){int flag=1;for(int l=j+1;l<=n;++l){if((bit>>(l*2))%4==1) flag++;if((bit>>(l*2))%4==2) flag--;if(!flag){insert(bit-inc[j]-inc[j-1]-inc[l],num);break;}}}else if(b1==2&&b2==2){int flag=1;for(int l=j-2;l>=0;--l){if((bit>>(l*2))%4==1) flag--;if((bit>>(l*2))%4==2) flag++;if(!flag){insert(bit-inc[j]*2-inc[j-1]*2+inc[l],num);break;}}}else if(b1==2&&b2==1) insert(bit-inc[j-1]*2-inc[j],num);else if (i==n&&j==n) {if (num<ans) ans=num;}else if (i==n&&j==n-1){long long b3=(bit>>(j*2+2))%4;if (b3==0&&num<ans) ans=num;}}}}
}
int main()
{int t;scanf("%d",&t);while (t--){ init();solve();printf("%lld\n",sum-ans);}return 0;
}

电脑前这个努力的帅气身影是谁呢?そう 私 です

好学易懂 从零开始的插头DP(三)相关推荐

  1. [入门向选讲] 插头DP:从零概念到入门 (例题:HDU1693 COGS1283 BZOJ2310 BZOJ2331)

    转载请注明原文地址:http://www.cnblogs.com/LadyLex/p/7326874.html 最近搞了一下插头DP的基础知识--这真的是一种很锻炼人的题型-- 每一道题的状态都不一样 ...

  2. P3272 [SCOI2011]地板(插头DP)

    [题面链接] https://www.luogu.org/problemnew/show/P3272 [题目描述] 有一个矩阵,有些点必须放,有些点不能放,用一些L型的图形放满,求方案数 [题解] ( ...

  3. 插头DP 概率DP / 期望DP

    插头DP && 概率DP / 期望DP 写在前面: 插头DP P5056 [模板]插头dp 手写哈希表的方法: 拉链法的代码如下: 开放寻址法的代码如下: 接下来是这道题的代码实现: ...

  4. NEFU 155 超弦(插头DP)

    超弦 Time Limit 5000ms Memory Limit 65536K description 前阵子hh看了一系列科普片<<优雅的宇宙>>,惊讶的发现整个世界都是由 ...

  5. bzoj1814 Ural 1519 Formula 1(插头dp模板题)

    1814: Ural 1519 Formula 1 Time Limit: 1 Sec  Memory Limit: 64 MB Submit: 924  Solved: 351 [Submit][S ...

  6. HDU4084 插头dp

    题意:给定一个图,0是不能放的,然后现在有1X1和1X2方块,最后铺满该图,使得1X1使用次数在C到D之间,1X2次数随便,问有几种放法 思路:插头DP或轮廓线,多加一维DP讨论就可以 注意插头DP状 ...

  7. POJ3133(插头dp)

    传送门:http://poj.org/problem?id=3133 Manhattan Wiring Time Limit: 5000MS   Memory Limit: 65536K       ...

  8. 微信小程序从零开始开发步骤(三)底部导航栏

    上一章节,我们分享了如何创建一个新的页面和设置页面的标题,这一章我们来聊聊底部导航栏是如何实现的.即点击底部的导航,会实现不同对应页面之间的切换. 我们先来看个我们要实现的底部导航栏的效果图:(三个导 ...

  9. POJ 3133 Manhattan Wiring (插头DP)

    Manhattan Wiring Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 1110   Accepted: 634 D ...

最新文章

  1. 【TensorFlow2.0】(6) 数据统计,范数、最值、求和、均值、最值位置、唯一值、张量比较
  2. python制作一个教学网站_小白如何入门Python? 制作一个网站为例
  3. 保险条款精解(二) 丢车——如何将损失降到最低点?
  4. HttpURLConnection与HttpClient提交FORM表单参数请求工具类
  5. mysql无法启动服务,错误1067
  6. 人工智能+教育的应用——教育的安全
  7. App专项测试之弱网测试
  8. 一键伪装成 Windows 10:Kali Linux 2019.4 版本推出 “Undercover” 模式
  9. Pyhton学习——Day33
  10. TXSQL:云计算时代数据库核弹头——云+未来峰会开发者专场回顾
  11. Linux查看硬盘序列号
  12. matlab视频文件处理,Matlab处理视频文件1
  13. php yar 安装失败_CentOS搭建Yar框架以及遇到的坑!
  14. throws和throw的作用
  15. 亚马逊云科技 AI For Good-2022优秀方案开源分享——望楼
  16. 简单易懂!!shell循环语句!for、while、until
  17. PLC学习第一篇:PLC程序架构
  18. (Win8、Win7)MAK激活密钥分享【资源有限】
  19. 铁死亡细胞实验相关抑制剂、激动剂
  20. 一篇学会:mysql锁表查询和解锁操作

热门文章

  1. python爬虫需要啥编程基础吗_编程办公Python爬虫零基础到爬啥都行
  2. JavaScript 取整的几种方法
  3. 最长上升子序列(acwing 895 acwing 896 acwing1017)
  4. 前端面试-主流浏览器以及其内核
  5. Python实现信用评分模型
  6. 我们公司由于员工失误,发错了产品型号,造成客户工程延期。请帮我们给客户写一封道歉信,需要态度诚恳,感情真挚,需要多谢一些内容,至少500个字...
  7. vue表单自定义校验规则
  8. 零基础入门UI设计,如何提升审美能力呢?
  9. 达人评测 荣耀MagicBook V 14怎么样
  10. android imageview缩小,android Imageview 缩小整个高度。