1. 程式人生 > >幫助BSNY(狀態壓縮+4維dp+滾動數組)

幫助BSNY(狀態壓縮+4維dp+滾動數組)

string scan ++ cstring pac str != return 改變

懵逼題,一度推出六維的DP,最後看了題解。。

恍然大悟。。。(需要運用好題目的限制(a[i]>=25 且a[i]<=32))並將相同的a[i]進行壓縮,壓縮成一個值

因為拿出一本書只有兩種可能,(1)放到最前面,(2)放到與它相同編號的書的旁邊,那麽我們可以就此加上限制,就可以推出狀態轉移方程式了(PS:每次拿書必須是一團一團地取出來,否則並不改變原狀態)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define
ll long long using namespace std; ll n,k,a[10005],h[100005],x,ans,flag[100005],sum[10005],f[2][105][10][1<<8],tot,all,p[10005]; int main(){ scanf("%lld%lld",&n,&k); for (int i=1; i<=n; i++) scanf("%lld",a+i),a[i]-=24; for (int i=1; i<=n; i++) { if (a[i]!=a[i-1]) h[++tot]=a[i]; sum[tot]
++; } for (int i=tot; i; i--){ if (flag[h[i]]) p[i]=1; flag[h[i]]=1; } memset(f[0],127,sizeof(f[0])); f[0][0][0][0]=0; all=(1<<8)-1; for (int i=1; i<=tot; i++) { x=x^1; memset(f[x],127,sizeof(f[x])); for (int j=0; j<=k; j++)
for (int w=0; w<=8; w++) for (int m=0; m<=all; m++) { if (f[x^1][j][w][m]>n) continue; f[x][j][h[i]][m|(1<<(h[i]-1))]=min(f[x][j][h[i]/*當前的最後一位是h[i]*/][m|(1<<(h[i]-1))],f[x^1][j][w][m]+(h[i]!=w));//當前的狀態等於之前的狀態+(判斷此時掃描的位是否等於原先的最後一位) if (j+sum[i]>k) continue; f[x][j+sum[i]][w][m|(1<<(h[i]/*將所有的相同值的合並後得到的*/-1)/*h[i]-1表示h[i]是否被取過了,與mor一下表示當前的狀態*/)]=min(f[x][j+sum[i]][w][m|(1<<(h[i]-1))],f[x^1][j][w][m]+!(m&(1<<(h[i]-1)))); if (p[i]) f[x][j+sum[i]/*改變為j+sum[i]次之後的狀態*/][w][m]=min(f[x][j+sum[i]/*改變為j+sum[i]次之後的狀態*/][w][m],f[x^1][j][w][m]); } } //每次x進行^操作是為了創造出滾動數組,即本次的狀態只跟上一次的狀態有關 ans=124278904761894269; for (int i=0; i<=k; i++) for (int w=0; w<=8; w++) for (int m=0; m<=all; m++) ans=min(ans,f[x][i][w][m]); printf("%lld\n",ans); return 0; }

幫助BSNY(狀態壓縮+4維dp+滾動數組)