@ysner
2018-08-05T21:16:52.000000Z
字数 1436
阅读 2387
DP
给定个二元组,问有多少种方案,使得选出其中几个后,。
在打比赛时又被傻逼DP切了
考虑到我们关注的是,我们可以维护一维状态以代替两维状态。
于是设表示在第个数中,的方案数。
可以为负,记得开大空间。
转移显然。
但有几个要注意的地方。
如果暴力枚举,复杂度可以达到,数据没有保证这样能过。
注意到中有很多转移是从不合法状态转移到不合法状态。
既然开始状态为(防止状态出现负数),范围很小。我们可以维护一下当前被转移到了的区间范围,这样能大大降低时间复杂度。
还有,值的边界条件要求必须能把未转移到的状态和转移到的状态区分开来。
所以初始所有值要设为,除外。
// luogu-judger-enable-o2
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#define re register
#define il inline
#define ll long long
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define fp(i,a,b) for(re int i=a;i<=b;i++)
#define fq(i,a,b) for(re int i=a;i>=b;i--)
using namespace std;
const int N=2e6+100,M=1e6;
int n,m,s[N],c[N],len,dp[2][N];
char a[N];
il ll gi()
{
re ll x=0,t=1;
re char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
if(ch=='-') t=-1,ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
return x*t;
}
int main()
{
n=gi();
fp(i,1,n)
{
scanf("%s",a+1);len=strlen(a+1);
fp(j,1,len) if(a[j]=='s') s[i]++;else if(a[j]=='c') c[i]++;
}
re int now=1,nxt=0,lasx=M,lasm=M,mn=M,mx=M;
memset(dp,-63,sizeof(dp));dp[1][M]=0;
fp(i,1,n)
{
swap(now,nxt);
fp(j,lasm,lasx)
{
dp[now][j+s[i]-c[i]]=max(dp[now][j+s[i]-c[i]],dp[nxt][j]+s[i]);
dp[now][j]=max(dp[now][j],dp[nxt][j]);
dp[nxt][j]=0;
mx=max(mx,j+s[i]-c[i]),mn=min(mn,j+s[i]-c[i]);
}
lasx=mx;lasm=mn;
}
printf("%d\n",dp[now][M]);
return 0;
}