终于切了第一道广义路径的题目,也确实感到比较复杂,最小表示法的优势也可以体现出来,因为这题,昨天的澡到现在才洗完,按照小hh的思路,用一条轮廓线记录联通状态,注意这里的轮廓线已经不是m+1啦,因为我们不需要左插头了,每个格子可以插至多4个插头,另外一条轮廓线表示当前的染色状态,这个要m+1因为还要保留左上格子的颜色,然后我们对于4个格子的颜色讨论,左,上,左上,当前,一共16中情况,8种是对称的,同时要注意一种情况,已经轮廓线上部已经有一个单独的联通块。说说我debug这么久是为什么吧,先是cs打成cl,问题是前4个sample尽然过啦,后面的sample爆了,后来发现改之,然后就开始纠结最后一个sample,对不上,一直到今天早上,我拿网上代码对拍,发现m=8的时候结果都不对,其他都是对的,查看代码数遍,直到刚刚,突然意识到,我的状态爆了,我最小表示法用二进制3位表示,范围0~7,我sb的从1开始标号,那么m=8时,12345678最大的标号就是这样,出现了8,坑爹了,改之,果然sample过了,提交1y,刷进了第一版
Ranking | Submission | Run Time | Language | Submission Date |
5 | 10710525 | 0.360 | C++ | 2012-10-10 05:40:30 |
#include<cstdio> #include<cstring> #include<string> #include<cmath> #include<iostream> #include<algorithm> #define LL long long using namespace std; const int maxn=10007; int pre[9][9][maxn]; bool res[9][9][maxn]; int bin[20],code[20]; struct node { int size,head[maxn],next[maxn]; LL sta[maxn],clo[maxn],sum[maxn]; void clear() { memset(head,-1,sizeof(head)); size=0; } void push(LL st,const LL v,LL cs,int x,int y,bool cl,int k) { int hash=((st*13)+cs)%maxn; for(int i=head[hash];i>=0;i=next[i]) { if(sta[i]==st&&clo[i]==cs) { sum[i]+=v; return ; } } sta[size]=st,clo[size]=cs,sum[size]=v; res[x][y][size]=cl,pre[x][y][size]=k; next[size]=head[hash],head[hash]=size++; } }dp[2]; LL encode(int m) { LL st=0,cnt=0; memset(bin,-1,sizeof(bin)); for(int i=m-1;i>=0;i--) { if(bin[code[i]]==-1) bin[code[i]]=cnt++; code[i]=bin[code[i]]; st<<=3; st|=code[i]; } return st; } void decode(LL st,int m) { for(int i=0;i<m;i++) { code[i]=st&7; st>>=3; } } int n,m,now,old; char gp[20][20]; bool check(LL cs,int x,int y,int m,int nc) { int cnt=0,cnt1=0; for(int i=0;i<m;i++) { if(code[i]==code[y]) cnt++; if(((cs>>i)&1)==(nc^1)) cnt1++; } if(cnt==1) { if(cnt1>1) return false; char ch=nc==1?'o':'#'; for(int i=x-1;i<n;i++) for(int j=i==x-1?y+1:0;j<m;j++) { if(gp[i][j]==ch) return false; if(i+1<n&&j+1<m) return false; } } return true; } void DP(int x,int y,int nc) { for(int k=0;k<dp[old].size;k++) { bool l=y==0?0:((dp[old].clo[k]>>(y-1))&1)==nc; bool up=x==0?0:((dp[old].clo[k]>>y)&1)==nc; bool lp=(x==0||y==0)?0:((dp[old].clo[k]>>m)&1)==nc; decode(dp[old].sta[k],m); if(x&&!up&&!check(dp[old].clo[k],x,y,m,nc)) continue; if(!l&&!up&&!lp) code[y]=10; else if(l&&!up&&!lp) code[y]=code[y-1]; else if(!l&&up&&!lp) code[y]=code[y]; else if(!lp&&l&&up) { if(code[y-1]!=code[y]) { for(int i=0,id=code[y];i<m;i++) if(code[i]==id) code[i]=code[y-1]; } } else if(lp&&!up&&!l) { if(x==n-1&&y==m-1) continue; code[y]=10; } else if(lp&&l&&!up) code[y]=code[y-1]; else if(lp&&up&&!l) code[y]=code[y]; else continue; LL cs=dp[old].clo[k]&(~(1<<y))&(~(1<<m)); if(nc) cs|=1<<y; if((up==0&&nc==0)||(up==1&&nc==1)) cs|=1<<m; dp[now].push(encode(m),dp[old].sum[k],cs,x,y,nc,k); } } void slove() { dp[0].clear(); dp[0].push(0,1,0,n,m,0,-1); now=0,old=1; for(int i=0;i<n;i++) for(int j=0;j<m;j++) { old=now,now^=1,dp[now].clear(); if(gp[i][j]!='#') DP(i,j,0); if(gp[i][j]!='o') DP(i,j,1); } int flag=-1,ans=0; for(int i=0;i<dp[now].size;i++) { decode(dp[now].sta[i],m); int cnt=0; memset(bin,-1,sizeof(bin)); for(int j=0;j<m;j++) { if(bin[code[j]]==-1) bin[code[j]]=cnt++; } if(cnt<=2) { flag=i; ans+=dp[now].sum[i]; } } if(flag==-1) puts("0\n"); else { printf("%d\n",ans); for(int i=n-1;i>=0;i--) for(int j=m-1;j>=0;j--) { gp[i][j]=res[i][j][flag]==0?'o':'#'; flag=pre[i][j][flag]; } for(int i=0;i<n;i++) { for(int j=0;j<m;j++) printf("%c",gp[i][j]); puts(""); } puts(""); } } int main() { int T; scanf("%d",&T); while(T--) { scanf("%d%d",&n,&m); for(int i=0;i<n;i++) { scanf("%s",gp[i]); } slove(); } return 0; }