【GDOI2018模拟7.10】B

xiaoxiao2021-02-28  72

Description

Solution

其实这是一道很简单的题目,但是想法非常的机智。 很显然有一个DP方程设f[i][j]表示前i个只填前i个数,最后一个数是j的方案数。 我们想一想怎样把i+1放进去且使得它合法且不重复不遗漏。 在排列的问题上很显然有一个方法是把i+1插入到前面去,但是这样不一定合法且位置不好找。我们可以知道前面f[i]的状态全都是1~i的排列,如果我们现在最后一位要放j,那么把大于等于j的数同时+1,就可以把i+1插进去了且合法。 所以我们现在可以对最后面那个位置的字符分类讨论一下。 转移到i+1 如果是U那么既然要填j,就可以由f[i][1~j-1]转移过来。 如果是I那么既然要填j,因为大于等于j的都要加1(要是+1后都>j的数),所以可以由f[i][j~i]转移过来 如果是?那么两个加起来。 所以再维护一个前缀和就好了。

Code

#include<iostream> #include<stdio.h> #include<string.h> #include<algorithm> #include<math.h> #define fo(i,a,b) for(i=a;i<=b;i++) using namespace std; typedef long long ll; const int maxn=1007,mo=1e9+7; ll i,j,k,l,t,n,m; char s[maxn]; ll f[maxn][maxn],g[maxn][maxn],ans; int main(){ scanf("%s",s+1);n=strlen(s+1); f[1][1]=1;g[1][1]=1; fo(i,1,n){ fo(j,1,i+1){ if(s[i]=='D'||s[i]=='?'&&i>=j)f[i+1][j]=(f[i+1][j]+g[i][i]-g[i][j-1])%mo; if(s[i]=='I'||s[i]=='?')f[i+1][j]=(f[i+1][j]+g[i][j-1])%mo; g[i+1][j]=(g[i+1][j-1]+f[i+1][j])%mo; } } ans=g[n+1][n+1];ans=(ans+mo)%mo; printf("%lld\n",ans); }
转载请注明原文地址: https://www.6miu.com/read-30755.html

最新回复(0)