BZOJ4565 [Haoi2016]字符合並
阿新 • • 發佈:2018-11-22
end template pri 分析 減少 span 如果 amp 註意 串)
(由於每次合並會減少 \(k?1\) 個字符,故 \(S\) 的長度固定)
考慮 \(S\) 的每個字符,它們都是由原串的一個區間逐漸壓縮成的。
故 \(S\) 的每個字符互相獨立,互不影響。
我們就枚舉一個 \(mid∈[l,r)\) ,表示 \(S\) 的最後一個字符是由原串的區間 \((mid,r]\) 壓縮成的。
這時候就有一個非常傳統的區間 dp 轉移了!
以下把 \(mg(S,x)\) 定義為 \((S<<1)|x\) ,即在 \(S\) 的後面插入 \(x\) 。 \(x∈{0,1}\) 。
\[f[l][r][mg(S,x)]=max(f[l][r][mg(S,x)],f[l][mid][S]+f[mid+1][r][x])\]
其中 \(x∈{0,1}\) 。
註意上面針對的是 \(|S|=(r?l)mod(k?1)+1<k?1\) 的情況。
如果 \(|S|=k?1\) ,那麽 \([l,mid]\) 會和 \((mid,r]\) 組成一個長度為 \(k\) 的串,還可以再次合並。
故當 \(|S|=k?1\) 時:
\[ f[l][r][c[mg(S,x)]]=max(f[l][r][c[mg(S,x)]],f[l][mid][S]+f[mid+1][r][x]+w[mg(S,x)]) \]
同樣 \(x∈{0,1}\)
理論復雜度\(O(2^k \cdot n^3)\) ,但實際狀態沒有那麽多。
題意
有一個長度為\(n\)的\(01\)串,你可以每次將相鄰的\(k\)個字符合並,得到一個新的字符並獲得一定分數。得到的新字符和分數由這\(k\)個字符確定。你需要求出你能獲得的最大分數。
\(n \leq 300,k \leq 8,1 \leq w_i \leq 10^9\)
分析
參照xyz32768的題解。
區間合並讓人想到區間 dp ,而 \(k≤8\) 又讓人想到狀壓 dp 。
我們考慮合二為一。
\(f[l][r][S]\) 表示將區間 \([l,r]\) 內的字符不斷合並,最後變成串 \(S\) 的最大收益。
( \(S\) 是一個長度為 \((r?l)mod(k?1)+1\) 的 \(01\)
(由於每次合並會減少 \(k?1\) 個字符,故 \(S\) 的長度固定)
考慮 \(S\) 的每個字符,它們都是由原串的一個區間逐漸壓縮成的。
故 \(S\) 的每個字符互相獨立,互不影響。
我們就枚舉一個 \(mid∈[l,r)\) ,表示 \(S\) 的最後一個字符是由原串的區間 \((mid,r]\) 壓縮成的。
這時候就有一個非常傳統的區間 dp 轉移了!
以下把 \(mg(S,x)\) 定義為 \((S<<1)|x\) ,即在 \(S\) 的後面插入 \(x\) 。 \(x∈{0,1}\) 。
\[f[l][r][mg(S,x)]=max(f[l][r][mg(S,x)],f[l][mid][S]+f[mid+1][r][x])\]
其中 \(x∈{0,1}\) 。
註意上面針對的是 \(|S|=(r?l)mod(k?1)+1<k?1\) 的情況。
如果 \(|S|=k?1\) ,那麽 \([l,mid]\) 會和 \((mid,r]\) 組成一個長度為 \(k\) 的串,還可以再次合並。
故當 \(|S|=k?1\) 時:
\[ f[l][r][c[mg(S,x)]]=max(f[l][r][c[mg(S,x)]],f[l][mid][S]+f[mid+1][r][x]+w[mg(S,x)]) \]
同樣 \(x∈{0,1}\)
理論復雜度\(O(2^k \cdot n^3)\) ,但實際狀態沒有那麽多。
代碼
#include<iostream> #include<cstdio> #include<cstdlib> #include<cmath> #include<set> #include<map> #include<queue> #include<stack> #include<algorithm> #include<cstring> #define rg register #define il inline #define co const template<class T>T read() { T data=0; int w=1; char ch=getchar(); while(!isdigit(ch)) { if(ch=='-') w=-1; ch=getchar(); } while(isdigit(ch)) { data=data*10+ch-'0'; ch=getchar(); } return data*w; } template<class T>T read(T&x) { return x=read<T>(); } using namespace std; typedef long long ll; co int MAXN=300,MAXK=8; int n,k; int a[MAXN]; int c[1<<MAXK],w[1<<MAXK]; ll f[MAXN][MAXN][1<<MAXK]; int main() { // freopen(".in","r",stdin); // freopen(".out","w",stdout); read(n);read(k); for(int i=0;i<n;++i) read(a[i]); for(int i=0;i<(1<<k);++i) { read(c[i]);read(w[i]); } memset(f,-1,sizeof f); for(int i=0;i<n;++i) f[i][i][a[i]] = 0; for(int i=n-1;i>=0;--i) for(int j=i+1;j<n;++j) { int len = (j - i) % (k - 1) + 1; if(len > 1) { for(int mid = i + len - 2;mid <= j - 1;mid += k - 1) for(int s = 0;s < (1 << (len - 1));++s) { if(f[i][mid][s]==-1) continue; if(f[mid+1][j][0]!=-1) f[i][j][s<<1] = max(f[i][j][s<<1],f[i][mid][s]+f[mid+1][j][0]); if(f[mid+1][j][1]!=-1) f[i][j][s<<1|1] = max(f[i][j][s<<1|1],f[i][mid][s]+f[mid+1][j][1]); } } else { for(int s = 0;s < (1 << (k - 1));++s) for(int mid = i + k - 2;mid <= j - 1;mid += k - 1) { if(f[i][mid][s]==-1) continue; if(f[mid+1][j][0]!=-1) f[i][j][c[s<<1]]=max(f[i][j][c[s<<1]],f[i][mid][s]+f[mid+1][j][0]+w[s<<1]); if(f[mid+1][j][1]!=-1) f[i][j][c[s<<1|1]]=max(f[i][j][c[s<<1|1]],f[i][mid][s]+f[mid+1][j][1]+w[s<<1|1]); } } } ll ans=-1; for(int i=0;i<(1<<k);++i) { // cerr<<i<<" f="<<f[0][n-1][i]<<endl; ans=max(ans,f[0][n-1][i]); } printf("%lld\n",ans); return 0; }
BZOJ4565 [Haoi2016]字符合並