[atAGC054C]Roughly Sorted

考虑对于确定的排列$\{p_{i}\}$,如何求出其(交换后)会得到的排列——

令$cnt_{x}$为在$i$之前比$x$大的元素个数(其中$p_{i}=x$),显然排列合法当且仅当$cnt_{i}\le k$

注意到每一次交换至多只有初始靠后的元素$cnt_{i}$减小1,因此交换次数至少为$\sum_{i=1}^{n}\max(cnt_{i}-k,0)$

(这里可以简单分析一下交换对$cnt_{i}$的影响,方便理解)

另一方面,取$x=\min_{cnt_{i}>k}i$和$p_{i}=x$,此时必然有$p_{i-1}>p_{i}$(否则即与$x$最小矛盾),因此将$i$和$i-1$交换即可令$cnt_{x}$减小1(且其余$cnt_{i}$不变),重复此过程也即得到了下限

虽然取到下限的方式有很多种,但最终都有$cnt'_{i}=\min(cnt_{i},k)$

同时,对于一组$cnt_{i}\in [0,n-i]$的$\{cnt_{i}\}$,也能唯一确定对应的排列(从大到小依次插入数即可)

换言之,对于原问题来说,即统计有多少组$\{cnt_{i}\}$满足$cnt_{i}\in [0,n-i]$且$cnt'_{i}=\min(cnt_{i},k)$(其中$cnt'_{i}$为给出的排列得到的$cnt_{i}$),显然每一项独立,答案即为$\prod_{1\le i\le n,cnt_{i}=k}(n-i-k+1)$

(这里的构造与原题解略有不同,个人认为更容易理解QAQ)

时间复杂度为$o(n^{2})$或$o(n\log n)$(关于如何计算$cnt_{i}$),可以通过

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 5005
 4 #define mod 998244353
 5 #define ll long long
 6 int n,k,ans,p[N],cnt[N];
 7 int main(){
 8     scanf("%d%d",&n,&k);
 9     for(int i=1;i<=n;i++)scanf("%d",&p[i]);
10     for(int i=1;i<=n;i++)
11         for(int j=1;j<i;j++)
12             if (p[i]<p[j])cnt[p[i]]++;
13     ans=1;
14     for(int i=1;i<=n;i++)
15         if (cnt[i]==k)ans=(ll)ans*(n-i-k+1)%mod;
16     printf("%d\n",ans);
17     return 0;
18 } 
View Code

 

posted @ 2021-09-27 21:35  PYWBKTDA  阅读(154)  评论(1编辑  收藏  举报