1. 程式人生 > 其它 >P7532 [USACO21OPEN] Balanced Subsets P 題解

P7532 [USACO21OPEN] Balanced Subsets P 題解

P7532 [USACO21OPEN] Balanced Subsets P

sol

我們先解讀一下題目中給的限制條件,就是一個凸多邊形的形狀

單考慮左右邊界,發現是先增後減,或者一直往一個方向走

那麼我們可以寫一個 \(o(n^5)\) 的 DP ,定義 \(F[i][a][b][l(0/1)][r(0/1)]\) 表示
列舉到第 \(i\) 行,現在的左邊界是 \(a\),右邊界是 \(b\)\(l,r\)表示左右邊界是否遞增,\(0\) 表示增, \(1\)表示減

然後考慮轉移

if(x>=l&&y<=r)f[i][l][r][0][0]+=f[i-1][x][y][0][0];
if(x>=l&&x<=r&&y>r)f[i][l][r][0][1]+=f[i-1][x][y][0][0];
if(x>=l&&x<=r&&y>=r)f[i][l][r][0][1]+=f[i-1][x][y][0][1];
if(y>=l&&y<=r&&x<l)f[i][l][r][1][0]+=f[i-1][x][y][0][0];
if(y>=l&&y<=r&&x<=l)f[i][l][r][1][0]+=f[i-1][x][y][1][0];
if(x<=l&&y>=r)f[i][l][r][1][1]+=f[i-1][x][y][1][1];
if(x<l&&y>=r)f[i][l][r][1][1]+=f[i-1][x][y][0][1];
if(x<=l&&y>r)f[i][l][r][1][1]+=f[i-1][x][y][1][0];
if(x<l&&y>r)f[i][l][r][1][1]+=f[i-1][x][y][0][0];

考慮怎麼優化

我們發現,一種情況 \(l,r\) 要轉移到 \(l',r'\) 在每種 \(0/1\) 狀態下都是滿足某種關係,那麼我們可不可以將他們記錄下來呢

答案是可以的

\(l,r,l',r'\) 看成 二維平面中的一個點, \(l,r\) 分別對應兩個座標,那麼滿足條件的 \(l',r'\) 是二維平面中的一些矩陣區域

如圖,當 \(0,0\) 狀態,也就是兩邊都要遞增是,要滿足 \(l'<l,r'<r\) 也就是圖中區域

然後用二維字首和處理就好了

code

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn=155;
const LL TT=1e9+7;
int N,s[maxn];
LL f[maxn][maxn][maxn][2][2],g[maxn][maxn][maxn][2][2];
char ch[maxn];
LL ans=0;
inline int read(){
	int ret=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-f;ch=getchar();}
	while(ch<='9'&&ch>='0')ret=ret*10+ch-'0',ch=getchar();
	return ret*f;
}
int get(int i,int x,int y,int p,int q,int l,int r){
	return (((g[i][y][q][l][r]-g[i][x-1][q][l][r])%TT-g[i][y][p-1][l][r])%TT+g[i][x-1][p-1][l][r]+TT)%TT;
}
int main(){
	N=read();
	for(int i=1;i<=N;i++){
		scanf("%s",ch+1);
		for(int j=1;j<=N;j++) s[j]=s[j-1]+(ch[j]=='G');
		for(int l=N;l>=1;l--)
		for(int r=l;r<=N;r++)if(s[r]-s[l-1]==r-l+1){
			f[i][l][r][0][0]=1+get(i-1,l,r,l,r,0,0);
			f[i][l][r][0][1]=(get(i-1,l,r,r+1,N,0,0)+get(i-1,l,r,r,N,0,1))%TT;
			f[i][l][r][1][0]=(get(i-1,1,l-1,l,r,0,0)+get(i-1,1,l,l,r,1,0))%TT;
			f[i][l][r][1][1]=((get(i-1,1,l,r,N,1,1)+get(i-1,1,l-1,r+1,N,0,0))%TT+(get(i-1,1,l-1,r,N,0,1)+get(i-1,1,l,r+1,N,1,0))%TT)%TT;
			for(int ii=0;ii<=1;ii++)
			for(int jj=0;jj<=1;jj++)ans=(ans+f[i][l][r][ii][jj])%TT;
		}
		for(int p=0;p<=1;p++)
		for(int q=0;q<=1;q++)
		for(int x=1;x<=N;x++)
		for(int y=1;y<=N;y++)
			g[i][x][y][p][q]=(((g[i][x-1][y][p][q]+g[i][x][y-1][p][q])%TT-g[i][x-1][y-1][p][q])%TT+f[i][x][y][p][q])%TT;
	}
	printf("%lld\n",(ans+TT)%TT);
	return 0;
}