P3272 [SCOI2011]地板(插头DP)
[題面鏈接] https://www.luogu.org/problemnew/show/P3272
[題目描述] 有一個矩陣,有些點必須放,有些點不能放,用一些L型的圖形放滿,求方案數
[題解] (版權所有) https://www.luogu.org/blog/dedicatus545/solution-p3272
第一種情況:當前狀態下,當前格子上方和左方都沒有插頭
這時我們需要找一個L形來把這個格子填上,那么我們可能有三種決策:
決策一:給這個格子加一個二號下插頭和一個二號右插頭,此時這個格子是一個新的L形的拐角
決策二:給這個格子加一個一號下插頭,此時相當于構建了一個先向下再向右的L形,從當前格子開始
決策三:給這個格子加一個一號右插頭,此時相當于構建了一個先向右再向下的L形,從當前格子開始
第二種情況:當前狀態下,當前格子上方有一個一號下插頭,左方沒有插頭
這時相當于上面有一個L形的未拐彎的一邊伸過來了,有兩種決策:
決策一:L形不拐彎,繼續向下延伸,當前格子只有一個一號下插頭
決策二:L形在當前格子拐彎,L形向右延伸,當前格子只有一個二號右插頭
第三種情況:當前狀態下,當前格子左方有一個一號右插頭,上方沒有插頭
與第二種情況類似,故不贅述
第四種情況:當前狀態下,當前格子上方有一個二號下插頭,左方沒有插頭
這時相當于上面有一個L形的拐過彎的一邊伸過來了,有兩種決策:
決策一:L形繼續延伸,當前格子有一個二號下插頭
決策二:L形在當前格子終止,當前格子沒有插頭
決策二時注意,如果當前處在最后一個沒有障礙的格子,那么需要統計入最終答案
第五種情況:當前狀態下,當前格子左方有一個二號右插頭,上方沒有插頭
與第四種情況類似,故不贅述
第六種情況:當前狀態下,當前格子左方和上方都有一號插頭
此時相當于兩條“臂”伸了過來,在當前格子相交,應該合并成一個L形
當前格子相當于一個L形的拐彎處,沒有插頭
我們發現,情況一和情況六已經覆蓋了四種L形的擺放方式,同時也不會有一個二號插頭一個一號插頭或者兩個二號插頭的情況出現——它們被上文的六種情況限制了
故這種分類討論方式可以覆蓋所有情況
總結
\(1.\) 插頭定義在掃描線上方,定義處理前插頭在左上的上方,處理完當前點后對應的掃描線圖形后插頭在右下的上方
\(2.\) 插頭DP神題,注意分類討論,一般分類標準為向右向下延伸,而向左向上的情況則通過在某一個點合并上面和左邊傳來的
// https://www.luogu.org/blog/dedicatus545/solution-p3272 #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define hash deep_dark_fantasy #define ll long long #define MOD 20110520 using namespace std; inline int read(){int re=0,flag=1;char ch=getchar();while(ch>'9'||ch<'0'){if(ch=='-') flag=-1;ch=getchar();}while(ch>='0'&&ch<='9') re=(re<<1)+(re<<3)+ch-'0',ch=getchar();return re*flag; } int n,m,x[150][150],cur,pre,ex,ey; int st[2][300010];ll ans[2][300010],re; int tot[2],bit[20],state[300010],st_tot,hash=300000; struct edge{int to,next; }a[300010]; void insert(int now,ll val){int p=now%hash;for(int i=state[p];i;i=a[i].next){if(st[cur][a[i].to]==now){ans[cur][a[i].to]+=val;ans[cur][a[i].to]%=MOD;return;}}tot[cur]++;a[++st_tot].to=tot[cur];a[st_tot].next=state[p];state[p]=st_tot;st[cur][tot[cur]]=now;ans[cur][tot[cur]]=val%MOD; } void dp(){int i,j,k,down,right,now;ll val;cur=0;tot[cur]=1;ans[cur][1]=1;st[cur][1]=0;for(i=1;i<=n;i++){for(j=1;j<=tot[cur];j++) st[cur][j]<<=2;for(j=1;j<=m;j++){memset(state,0,sizeof(state));st_tot=0;pre=cur;cur^=1;tot[cur]=0;for(k=1;k<=tot[pre];k++){now=st[pre][k];val=ans[pre][k];right=(now>>bit[j-1])%4;down=(now>>bit[j])%4;if(!x[i][j]){//障礙格子if(!down&&!right){insert(now,val);continue;}}if(!right&&!down){//第一種情況if(x[i+1][j]&&x[i][j+1])insert(now+((1<<bit[j-1])<<1)+((1<<bit[j])<<1),val);if(x[i+1][j]) insert(now+(1<<bit[j-1]),val);if(x[i][j+1]) insert(now+(1<<bit[j]),val);}if(right==1&&!down){//第三種情況if(x[i][j+1]) insert(now-(1<<bit[j-1])+(1<<bit[j]),val);if(x[i+1][j]) insert(now+(1<<bit[j-1]),val);}if(down==1&&!right){//第二種情況if(x[i+1][j]) insert(now-(1<<bit[j])+(1<<bit[j-1]),val);if(x[i][j+1]) insert(now+(1<<bit[j]),val);}if(right==2&&!down){//第五種情況if(i==ex&&j==ey) re+=val,re%=MOD;if(x[i][j+1]) insert(now-((1<<bit[j-1])<<1)+((1<<bit[j])<<1),val);insert(now-((1<<bit[j-1])<<1),val);}if(down==2&&!right){//第四種情況if(i==ex&&j==ey) re+=val,re%=MOD;if(x[i+1][j]) insert(now-((1<<bit[j])<<1)+((1<<bit[j-1])<<1),val);insert(now-((1<<bit[j])<<1),val);}if(down==1&&right==1){//第六種情況if(i==ex&&j==ey) re+=val,re%=MOD;insert(now-(1<<bit[j-1])-(1<<bit[j]),val);}}}} } int main(){//這道題的讀入沒有保證n>=m,所以我寫了一個判斷,來保證n>=m,具體操作就是把圖旋轉了九十度int i,j;char ch;n=read();m=read();for(i=1;i<=20;i++) bit[i]=i<<1;if(n>m){for(i=1;i<=n;i++){for(j=1;j<=m;j++){ch=getchar();while(ch!='*'&&ch!='_') ch=getchar();x[i][j]=(ch=='_');if(x[i][j]) ex=i,ey=j;}}}else{swap(n,m);for(i=m;i>0;i--){for(j=1;j<=n;j++){ch=getchar();while(ch!='*'&&ch!='_') ch=getchar();x[j][i]=(ch=='_');if(x[j][i]&&((j>ex)||(j==ex&&i>ey))) ex=j,ey=i;}}}dp();printf("%lld",re); }轉載于:https://www.cnblogs.com/lizehon/p/10420606.html
總結
以上是生活随笔為你收集整理的P3272 [SCOI2011]地板(插头DP)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 浏览器登陆时纪录自动登陆时限
- 下一篇: react+ant design Bre