题解:[ARC112E] Cigar Box
前言
好题,很可做也很有意思。
思路分析
首先发现如果一个点被操作了多次,那么只有最后一次会影响它的位置。
我们称影响位置的操作为有效操作,不影响位置的为无效操作。
不难发现,序列可以分为三部分,前面部分是往前放的有效操作,中间部分是没有移动过的,后面部分是往后放的有效操作。
于是可以考虑一个 DP,设 \(f_{i,l,r}\) 表示从后往前考虑操作,目前填了 \(i\) 个,有 \(l\) 个往前放的有效操作,有 \(r\) 个往后放的有效操作。转移为:
\[f_{i,l,r}=2(l+r)f_{i-1,l,r}+f_{i-1,l-1,r}+f_{i-1,l,r-1}
\]
前一部分表示第 \(i\) 次操作是无效操作,那么它可以放到序列中任意位置,任意方向;
后两部分表示第 \(i\) 次操作是有效操作,因为变换后的序列是唯一的,所以这次操作也是唯一的。
统计答案时,需要考虑中间的部分是否合法,也就是 \(a[l+1,n-r]\) 是否单调递增。
考虑进一步优化。
发现 \(f_{i,l,r}\) 的转移之和 \((l+r)\) 有关,也就是说 \(l+r\) 相等的 \(f_{i,l,r}\) 的值是一样的。
这启发我们改进 DP,设 \(g_{i,j}\) 表示从后往前考虑操作,目前填了 \(i\) 个,有 \(j\) 个有效操作。转移为:
\[g_{i,j}=g_{i-1,j-1}+2jg_{i-1,j}
\]
在统计答案时,因为没有钦定 \(j\) 次有效操作的顺序,所以 \(f_{i,l,r}=\binom{l+r}{l}g_{i,l+r}\)。
复杂度 \(O(nm)\)。
代码实现
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int mod=998244353;
int n,m,ans,a[3005],f[3005][3005],c[3005][3005],vis[3005][3005];
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i];
}
f[0][0]=1;
for(int i=1;i<=m;i++){
for(int j=0;j<=n;j++){
f[i][j]=((j?f[i-1][j-1]:0)+2*j*f[i-1][j]%mod)%mod;
}
}
for(int i=1;i<=n;i++){
for(int j=i;j<=n;j++){
if(i!=j && a[j-1]>a[j]) break;
vis[i][j]=1;
}
}
c[0][0]=1;
for(int i=1;i<=m;i++){
c[i][0]=1;
for(int j=1;j<=i;j++){
c[i][j]=(c[i-1][j-1]+c[i-1][j])%mod;
}
}
for(int i=0;i<=n;i++){
for(int j=0;j<=n;j++){
if(i+1>n-j || vis[i+1][n-j]) ans=(ans+f[m][i+j]*c[i+j][i]%mod)%mod;
}
}
cout<<ans;
return 0;
}

浙公网安备 33010602011771号