P9108 [PA2020] Malowanie płotu 题解

题目传送门

简单 dp 题。

直接 dp,记 $f_{i,j}$ 表示前 $i$ 列,第 $i$ 列区间的右端点 $\le j$ 的方案数,$g_{i,j}$ 表示前 $i$ 列,第 $i$ 列区间的左端点 $\ge j$ 的方案数。

如果第 $i$ 列的区间为 $[l,r]$,那么贡献就是 $f_{i-1,m}-f_{i-1,l-1}-g_{i-1,r+1}$,于是维护个前缀和直接转移即可,状态使用滚动数组记录即可通过。

时间复杂度 $O(nm)$。

参考代码:

#include<bits/stdc++.h>
#define ll long long
#define mxn 10000003
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define rept(i,a,b) for(int i=a;i<b;++i)
#define drep(i,a,b) for(int i=a;i>=b;--i)
using namespace std;
int n,m,md,f1[2][mxn],f2[2][mxn];
bool fl;
signed main(){
    cin>>n>>m>>md;
    rep(i,1,m)f1[0][i]=(f1[0][i-1]+i)%md;
    drep(i,m,1)f2[0][i]=(f2[0][i+1]+m-i+1)%md;
    rep(i,2,n){
        fl^=1;
        rep(j,0,m+1)f1[fl][j]=f2[fl][j]=0; 
        int s=0;
        rep(j,1,m){
            s=(s+f1[fl^1][j-1])%md;
            f1[fl][j]=(f1[fl][j-1]+(ll)f1[fl^1][m]*j-s-(ll)f2[fl^1][j+1]*j)%md;
        }
        s=0;
        drep(j,m,1){
            s=(s+f2[fl^1][j+1])%md;
            f2[fl][j]=(f2[fl][j+1]+f2[fl^1][1]*(m-j+1ll)-s-f1[fl^1][j-1]*(m-j+1ll))%md;
        }
    }
    cout<<(f1[fl][m]+md)%md;
    return 0;
}
posted @ 2024-01-08 14:09  zifanwang  阅读(14)  评论(0)    收藏  举报  来源