1. 程式人生 > >bzoj4922 [Lydsy1706月賽]Karp-de-Chant Number 貪心+dp

bzoj4922 [Lydsy1706月賽]Karp-de-Chant Number 貪心+dp

中文題自己看。

可以想到揹包,然後用:先放會使累計的左括號增加的,最後放會使累計的左括號減少的,先放的是按最大括號深度從小到大,後放的是按不計算被該塊右括號消去的增加的左括號從大到小,按這個順序排個序,就可以做消去限制的揹包了。

AC Code:

#define maxn 305
using namespace std;

int n,a[maxn],b[maxn],c[maxn],ct[maxn],tp[maxn];
inline bool cmp(const int u,const int v)
{ 
	if(tp[u]!=tp[v]) return tp[u] < tp[v];
	if(tp[u]==0) return a[u] < a[v];
	else return b[u] > b[v];
}
int dp[2][maxn*maxn+500];

int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		char ch[305];
		cin>>ch;
		int len = strlen(ch);
		for(int j=0;j<len;j++)
		{
			if(ch[j] == ')') 
			{
				if(b[i]) b[i]--,ct[i]+=2;
				else a[i]++;
			}
			else b[i] ++;
		}
		c[i]=i;
		if(a[i] < b[i]) tp[i] = 0;
		else tp[i] = 1;
	}
	sort(c+1,c+1+n,cmp);
	memset(dp,-0x3f,sizeof dp);
	int now=1,pre=0;
	dp[pre][0] = 0;
	for(int i=1;i<=n;i++,swap(now,pre))
	{
		for(int j=90000;j>=0;j--) dp[now][j] = dp[pre][j];
		for(int j=90000;j>=a[c[i]];j--)
			if(dp[pre][j] >= 0)
				dp[now][j+b[c[i]]-a[c[i]]] = max(dp[now][j+b[c[i]]-a[c[i]]] , dp[pre][j] + 2*a[c[i]] + ct[c[i]]);
	}
	printf("%d\n",max(0,dp[pre][0]));
}