这里会显示出您选择的修订版和当前版本之间的差别。
2020-2021:teams:legal_string:jxm2001:contest:agc_054 [2021/06/28 09:48] jxm2001 创建 |
2020-2021:teams:legal_string:jxm2001:contest:agc_054 [2021/06/28 10:33] (当前版本) jxm2001 |
||
---|---|---|---|
行 59: | 行 59: | ||
</hidden> | </hidden> | ||
+ | ===== C - Roughly Sorted ===== | ||
+ | ==== 题意 ==== | ||
+ | |||
+ | 给定一个 $1\sim n$ 的排序 $P$,每次操作可以交换相邻两个元素的位置。 | ||
+ | |||
+ | 要求用最少的操作使得对每个 $i$,最多有 $k$ 个 $j\lt i$ 满足 $P_j'\gt P_i'$。 | ||
+ | |||
+ | 现已知 $P'$,问存在多少个可能的最初的 $P$。 | ||
+ | |||
+ | ==== 解法 ==== | ||
+ | |||
+ | 记 $f_i=\sum_{j=1}^{i-1}[P_j\gt P_i]$,不难发现对每次操作最多可以使得某个 $f_i$ 减一,于是最少操作数的下限为 $\sum_{i=1}^n \max(f_i-k,0)$。 | ||
+ | |||
+ | 考虑找到最小的 $i$ 使得 $f_i\gt k$,不难发现此时一定有 $P_{i-1}\gt P_i$,否则一定有 $f_{i-1}=f_i\gt k$,与 $i$ 的最小性矛盾。 | ||
+ | |||
+ | 交换 $P_{i-1},P_i$,可以使得 $f_i$ 减一。于是可以证明 $\sum_{i=1}^n \max(f_i-k,0)$ 这个操作下限是可以取到的。 | ||
+ | |||
+ | 根据离散数学知识,知逆序数与排列存在一一对应关系,同时有 $f(i)\le n-P_i$。 | ||
+ | |||
+ | 同时,为了使得步数最少,对 $f(i)\lt k$ 的位置,他的初值应该不变。对 $f(i)=k$ 的位置,他的初值只需要满足 $f(i)\le n-P_i$。 | ||
+ | |||
+ | 于是不难发现答案为 $\prod_{f(i)=k} (n-P_i-f(i)+1)$,时间复杂度 $O(n\log n)$。 | ||
+ | |||
+ | <hidden 查看代码> | ||
+ | <code cpp> | ||
+ | const int MAXN=5e3+5,mod=998244353; | ||
+ | int c[MAXN]; | ||
+ | #define lowbit(x) ((x)&(-x)) | ||
+ | void add(int pos){ | ||
+ | while(pos<MAXN){ | ||
+ | c[pos]++; | ||
+ | pos+=lowbit(pos); | ||
+ | } | ||
+ | } | ||
+ | int query(int pos){ | ||
+ | int ans=0; | ||
+ | while(pos){ | ||
+ | ans+=c[pos]; | ||
+ | pos-=lowbit(pos); | ||
+ | } | ||
+ | return ans; | ||
+ | } | ||
+ | int a[MAXN],p[MAXN]; | ||
+ | int main() | ||
+ | { | ||
+ | int n=read_int(),k=read_int(),ans=1; | ||
+ | _for(i,0,n){ | ||
+ | a[i]=read_int(); | ||
+ | p[i]=i-query(a[i]); | ||
+ | add(a[i]); | ||
+ | if(p[i]==k) | ||
+ | ans=1LL*ans*(n-a[i]-p[i]+1)%mod; | ||
+ | } | ||
+ | enter(ans); | ||
+ | return 0; | ||
+ | } | ||
+ | </code> | ||
+ | </hidden> |