您的位置:首页 > 其它

[DP] ZROI 2017提高 5 T2. 石头剪刀布

2017-10-07 20:56 295 查看
杜老师的好题。考虑一个暴力的 DP : f[i][p0][p1][p2] 表示序列前 i 个元素,分别以 0,1,2 为结尾的最长胜利子序列长度。简单的转移。这样复杂度是O(n4) 的,怎么优化呢?

考虑到 p0,p1,p2 之间的差是很小的。因为可以在子序列头上删一两个得到以其他为结尾的子序列。在分析一下发现差不会超过 2 。然后就发现有用的状态只有 O(n2) 。就做好了。

这种减少冗余状态的思路很好。记得上次做过一题,求把给定串变成回文需要删的最小字符数,若删超过k个,就输出Fail ,也是这种思路。就是求原串和反串的最长公共子序列时,i,j的差不必超过 k 这样可以 O(nk) 出解。

还需要多做题。

#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=2015,MOD=998244353;
int n,f[maxn][maxn][4][4],ans[maxn];
bool a[maxn][3];
inline int max(int x,int y){ return x>y?x:y; }
int main(){
freopen("zroi5B.in","r",stdin);
freopen("zroi5B.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;i++){
char st[5]; scanf("%s",st); int len=strlen(st);
for(int j=0;j<=len-1;j++) a[i][st[j]-'0']=true;
}
f[0][0][0+2][0+1]=1;
for(int i=0;i<=n-1;i++)
for(int p0=0;p0<=i;p0++)
for(int j1=-2;j1<=1;j1++) if(0<=p0+j1&&p0+j1<=i)
for(int j2=-1;j2<=2;j2++) if(0<=p0+j2&&p0+j2<=i) if(f[i][p0][j1+2][j2+1]){
int p1=p0+j1, p2=p0+j2;
if(a[i+1][0]) (f[i+1][max(p0,p2+1)][p1-max(p0,p2+1)+2][p2-max(p0,p2+1)+1]+=f[i][p0][j1+2][j2+1])%=MOD;
if(a[i+1][1]) (f[i+1][p0][max(p1,p0+1)-p0+2][p2-p0+1]+=f[i][p0][j1+2][j2+1])%=MOD;
if(a[i+1][2]) (f[i+1][p0][p1-p0+2][max(p2,p1+1)-p0+1]+=f[i][p0][j1+2][j2+1])%=MOD;
}
for(int p0=0;p0<=n;p0++)
for(int j1=-2;j1<=1;j1++) if(p0+j1>=0)
for(int j2=-1;j2<=2;j2++) if(p0+j2>=0) (ans[max(max(p0,p0+j1),p0+j2)]+=f
[p0][j1+2][j2+1])%=MOD;
for(int i=1;i<=n;i++) printf("%d\n",ans[i]);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: