CF1204E Natasha, Sasha and the Prefix Sums [动态规划]

N a t a s h a ,   S a s h a   a n d   t h e   P r e f i x   S u m s Natasha,\ Sasha\ and\ the\ Prefix\ Sums Natasha, Sasha and the Prefix Sums

题目描述见链接 .


正 解 部 分 \color{red}{正解部分}

F [ i , j ] F[i, j] F[i,j] 表示 i i i 1 1 1, j j j − 1 -1 1 的答案, 从后往前 放置数字进行 状态转移

  • 放置 1 1 1: 对 F [ i , j ] F[i, j] F[i,j] 产生 F [ i − 1 , j ] + ( i − 1 + j i − 1 ) F[i-1, j] + \begin{pmatrix} i-1+j \\ i-1 \end{pmatrix} F[i1,j]+(i1+ji1) 的贡献 .

  • 放置 − 1 -1 1: 对 F [ i , j ] F[i, j] F[i,j] 产生 F [ i , j − 1 ] − ( ( i + j − 1 j − 1 ) − g [ i , j − 1 ] ) F[i, j-1] - \left( \begin{pmatrix} i+j-1 \\ j-1 \end{pmatrix} - g[i, j-1]\right) F[i,j1]((i+j1j1)g[i,j1]) 的贡献 .

  • 初值: F [ i , 0 ] = i F[i, 0] = i F[i,0]=i

其中 g [ i , j ] g[i, j] g[i,j] 表示 i i i 1 1 1, j j j − 1 -1 1 所组成的序列 最大前缀和 0 0 0 的方案数, 先考虑特殊情况,

  • i > j i > j i>j, g [ i , j ] = 0 g[i, j] = 0 g[i,j]=0 .
  • g [ 0 , 0 ] = 1 g[0, 0] = 1 g[0,0]=1

再考虑 i ≤ j i \le j ij 时, g [ i , j ] g[i, j] g[i,j] 能更新哪些状态,

  • 1 1 1 时, 若能更新 g [ i + 1 , j ] g[i+1, j] g[i+1,j], 则说明 i < j i < j i<j i ≤ j i \le j ij, 所以转移条件为 i < j i < j i<j .
  • − 1 -1 1 时, 若能更新 g [ i , j + 1 ] g[i, j+1] g[i,j+1], 则说明 i ≤ j i \le j ij i ≤ j + 1 i \le j+1 ij+1, 所以转移条件为 i ≤ j i \le j ij .

∴ i ≤ j \therefore i \le j ij 时, g [ i , j ] = g [ i − 1 , j ] + g [ i , j − 1 ] g[i, j] = g[i-1, j] + g[i, j-1] g[i,j]=g[i1,j]+g[i,j1] .

因为 i − 1 < j i-1 < j i1<j, g [ i − 1 , j ] g[i-1, j] g[i1,j] 一定是由于取 m a x max max 取到 0 0 0 的,
而原本最大前缀和为 0 0 0, 多放置一个 − 1 -1 1, 最大前缀和仍为 0 0 0,
因此当 i ≤ j i \le j ij 时, 放置 1 1 1 和 放置 − 1 -1 1 都可以转移到 g [ i , j ] g[i, j] g[i,j] .


O ( N ) O(N) O(N) 做法

这里咕掉了 …

#include<bits/stdc++.h>
#define reg register

const int maxn = 2e6 + 5;
const int mod = 998244853;

int N;
int M;
int Ans;
int f[maxn];
int fac[maxn];
int inv[maxn];
int ifac[maxn];

int C(int n, int m){ if(n < m) return 0; return 1ll*fac[n]*ifac[m]%mod*ifac[n-m]%mod; }

int main(){
        fac[0] = 1; for(reg int i = 1; i < maxn; i ++) fac[i]=1ll*fac[i-1]*i%mod;
        inv[1] = 1; for(reg int i = 2; i < maxn; i ++) inv[i] = ((-1ll*mod/i*inv[mod%i])%mod + mod) % mod;
        ifac[0] = 1; for(reg int i = 1; i < maxn; i ++) ifac[i] = 1ll*ifac[i-1]*inv[i] % mod;
        scanf("%d%d", &N, &M);
        for(reg int i = N; i; i --){
                if(M+i <= N) f[i] = C(N+M, N);
                else f[i] = C(N+M, M+i);
                int add = (f[i]-f[i+1] + mod) % mod;
                add = 1ll*add*i % mod; 
                Ans = (Ans + add) % mod;
        }
        printf("%d\n", Ans);
        return 0;
}

实 现 部 分 \color{red}{实现部分}

#include<bits/stdc++.h>
#define reg register

const int maxn = 4005;
const int mod = 998244853;

int N;
int M;
int inv[maxn];
int fac[maxn];
int ifac[maxn];
int F[maxn][maxn];
int g[maxn][maxn];

int C(int n, int m){ return 1ll*fac[n]*ifac[m]%mod*ifac[n-m]%mod; }

int main(){
        scanf("%d%d", &N, &M);
        inv[1] = 1; for(reg int i = 2; i < maxn; i ++) inv[i] = ((-1ll*mod/i*inv[mod%i])%mod + mod) % mod;
        fac[0] = 1; for(reg int i = 1; i < maxn; i ++) fac[i] = 1ll*fac[i-1]*i%mod;
        ifac[0] = 1; for(reg int i = 1; i < maxn; i ++) ifac[i] = 1ll*ifac[i-1]*inv[i] % mod;
        g[0][0] = 1;
        for(reg int i = 0; i <= N; i ++)
                for(reg int j = i; j <= M; j ++){
                        if(i < j) g[i+1][j] = (g[i+1][j] + g[i][j]) % mod;
                        if(i <= j) g[i][j+1] = (g[i][j+1] + g[i][j]) % mod;
                } 
        for(reg int i = 1; i <= N; i ++) F[i][0] = i;
        for(reg int i = 0; i <= N; i ++)
                for(reg int j = 1; j <= M; j ++){
                        int add =  (F[i][j-1] - ((C(i-1+j, j-1)-g[i][j-1])%mod+mod)%mod + mod) % mod;
                        F[i][j] = (F[i][j] + add) % mod;
                        if(!i) continue ;
                        add = (F[i-1][j] + C(i-1+j, i-1)) % mod;
                        F[i][j] = (F[i][j] + add) % mod;
                }
        printf("%d\n", F[N][M]);
        return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值