序列递推——cf1204E(好题)

/*
显然用dp[i][j]来表示i个1,j个-1的结果
dp[i][j]由dp[i-1][j]和dp[i][j-1]转移而来 
    即dp[i][j]对应的所有序列,都可以由dp[i-1][j]在前面加一个1或dp[i][j-1]在前面加一个-1得到,
         这里加在前面是因为更容易统计
          
        考虑1加在前面,那么对于任意一种(i-1,j)的排列,贡献都+1,C(i-1+j,j)
        考虑-1加在前面,那么对于某些(i,j-1)的排列,贡献-1
            考虑哪些不需要,前缀中-1的个数始终大于1的序列本来答案就是0,因此不需要-1

预处理这样的序列个数
    f[i][j]表示有i个1,j个-1时,前缀-1数量大于1的序列个数
    f[i][j]的来源有两种f[i][j-1],f[i-1][j]
    对于f[i][j]的每种序列,都可以由 f[i][j-1] 后加一个-1,或者 f[i-1][j]后面加一个1得到 
初始值:f[o][j]=1,f[i][j]=0,i>j
*/
#include <bits/stdc++.h>
#define N 2010
#define mod 998244853
#define For(i,x,y) for(int i=(x);i<=(y);++i)
#define Rof(i,x,y) for(int i=(x);i>=(y);--i)
using namespace std;
 
int C[N<<1][N<<1],dp[N][N],k[N][N];
 
inline int add(int x,int y){ return x+y>=mod?x+y-mod:x+y; }
inline int mns(int x,int y){ return x-y<0?x-y+mod:x-y; }
int main(){
    int n,m;
    scanf("%d%d",&n,&m);
    For(i,0,n+m){ 
        C[i][0]=1;
        For(j,1,i) C[i][j]=add(C[i-1][j],C[i-1][j-1]);
    }   
    For(i,1,m) k[0][i]=1;
    For(i,1,n) For(j,i,m) k[i][j]=add(k[i-1][j],k[i][j-1]);
    For(i,1,n) dp[i][0]=i;
    For(i,1,n)
        For(j,1,m)
            dp[i][j]=add(add(dp[i-1][j],C[i+j-1][j]),mns(dp[i][j-1],mns(C[i+j-1][i],k[i][j-1])));
    cout<<dp[n][m];
}

猜你喜欢

转载自www.cnblogs.com/zsben991126/p/11517365.html