题解:P17132 [ICPC 2025 Shanghai R] Yet another permutation problem
qingyun3926 · · 题解
一道水题
考虑采用区间动态规划,任意分割等价拆成多段独立区间,每段仅两种形态:原样、交换本段最大最小值。一组记录区间不拆分的形态数量,一组记录区间随意拆分的总方案。按区间由短到长计算,枚举分割位置合并左右方案,各段组合数相乘累加。仅最值位置可互换,其余数字顺序不变,最终完整区间全拆分总方案即为答案。
代码配有注释,请享用~
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int mod=998244353,MOD=998244353;
const int N=505,M=5000010,Q=5010;
int a[N],b[N];
int f[N][N][3],g[N][N][3];
inline int add(int x,int y){
return x+y>=mod?x+y-mod:x+y;
}
inline int sub(int x,int y){
return x>=y?x-y:x+mod-y;
}
void inc(int &x,int y){
x=(x+y)%mod;
}
void dec(int &x,int y){
x=(x-y+mod)%mod;
}
int findmn(int l,int r){
int pos=0;
for(int i=l;i<=r;i++)
if(!pos||b[i]<b[pos]) pos=i;
return pos;
}
int findmx(int l,int r){
int pos=0;
for(int i=l;i<=r;i++)
if(!pos||b[i]>b[pos]) pos=i;
return pos;
}
void solve(){
int n;
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
// 单点初始化
for(int i=1;i<=n;i++){
f[i][i][0]=f[i][i][1]=f[i][i][2]=1;
g[i][i][0]=g[i][i][1]=g[i][i][2]=1;
}
// 区间DP,按长度从小到大
for(int len=2;len<=n;len++){
for(int l=1;l+len-1<=n;l++){
int r=l+len-1;
for(int i=l;i<=r;i++) b[i]=a[i];
int p=findmn(l,r),q=findmx(l,r);
// 计算f[l][r][0]
f[l][r][0]=0;
if(p<q){
for(int i=p;i<=q-1;i++)
inc(f[l][r][0],1ll*f[l][i][1]*g[i+1][r][2]%mod);
for(int i=q;i<=r-1;i++)
dec(f[l][r][0],1ll*f[l][i][0]*g[i+1][r][0]%mod);
}else{
for(int i=q;i<=p-1;i++)
inc(f[l][r][0],1ll*f[l][i][2]*g[i+1][r][1]%mod);
for(int i=p;i<=r-1;i++)
dec(f[l][r][0],1ll*f[l][i][0]*g[i+1][r][0]%mod);
}
// f[l][r][1]:交换后min位置变成原max
b[p]=n;
int x=findmn(l,r);
f[l][r][1]=0;
if(x<p){
for(int i=x;i<=p-1;i++)
inc(f[l][r][1],1ll*f[l][i][1]*g[i+1][r][0]%mod);
for(int i=p;i<=r-1;i++)
dec(f[l][r][1],1ll*f[l][i][1]*g[i+1][r][0]%mod);
}else{
for(int i=p;i<=x-1;i++)
inc(f[l][r][1],1ll*f[l][i][0]*g[i+1][r][1]%mod);
for(int i=x;i<=r-1;i++)
dec(f[l][r][1],1ll*f[l][i][1]*g[i+1][r][0]%mod);
}
b[p]=a[p];
// f[l][r][2]:交换后max位置变成原min
b[q]=1;
int y=findmx(l,r);
f[l][r][2]=0;
if(q<y){
for(int i=q;i<=y-1;i++)
inc(f[l][r][2],1ll*f[l][i][0]*g[i+1][r][2]%mod);
for(int i=y;i<=r-1;i++)
dec(f[l][r][2],1ll*f[l][i][2]*g[i+1][r][0]%mod);
}else{
for(int i=y;i<=q-1;i++)
inc(f[l][r][2],1ll*f[l][i][2]*g[i+1][r][0]%mod);
for(int i=q;i<=r-1;i++)
dec(f[l][r][2],1ll*f[l][i][2]*g[i+1][r][0]%mod);
}
b[q]=a[q];
// g[l][r] = 合并所有分块的总方案
g[l][r][0]=f[l][r][0];
g[l][r][1]=f[l][r][1];
g[l][r][2]=f[l][r][2];
for(int i=l;i<=r-1;i++)
inc(g[l][r][0],1ll*f[l][i][0]*g[i+1][r][0]%mod);
for(int i=l;i<=p-1;i++)
inc(g[l][r][1],1ll*f[l][i][0]*g[i+1][r][1]%mod);
for(int i=p;i<=r-1;i++)
inc(g[l][r][1],1ll*f[l][i][1]*g[i+1][r][0]%mod);
for(int i=l;i<=q-1;i++)
inc(g[l][r][2],1ll*f[l][i][0]*g[i+1][r][2]%mod);
for(int i=q;i<=r-1;i++)
inc(g[l][r][2],1ll*f[l][i][2]*g[i+1][r][0]%mod);
}
}
cout<<g[1][n][0]<<'\n';
}
signed main(){
//freopen(".in","r",stdin);
//freopen(".out","w",stdout);
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
solve();
return 0;
}
通过记录