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;
}

浙公网安备 33010602011771号