【题解】康拓展开(养生题)
养生养生
编号 | 题目 | 状态 | 分数 | 总时间 | 内存 | 代码 / 答案文件 | 提交者 | 提交时间 |
---|---|---|---|---|---|---|---|---|
#528662 | #167. 康托展开 | Accepted | 100 | 1129 ms | 8060 K | C++ 11 (Clang) / 1.2 K | winlere | 2019-07-17 8:29:28 |
假如说我的排列是这样的
\[
2 \quad3 \quad4\quad5\quad1
\]
可以从左往右扫,扫到第一个时,发现这个位置不是\(1\),而是\(2\),说明至少经历了\((2-1)\times (5-1)!\)次排列才可能第一个是\(2\)。把第一个判断完之后,就剩下了一个子排列,是个子问题。不过要动态维护每个数在当前剩下的数的排名,开个值域线段树就好了。
//@winlere
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std; typedef long long ll;
inline int qr(){
register int ret=0,f=0;
register char c=getchar();
while(c<48||c>57)f|=c==45,c=getchar();
while(c>=48&&c<=57) ret=ret*10+c-48,c=getchar();
return f?-ret:ret;
}
const int mod=998244353;
const int maxn=1e6+5;
int jc[maxn],n;
int data[maxn];
#define lowbit(x) ((x)&(-(x)))
inline void add(const int&pos,const int&ad){
for(register int t=pos;t<=n;t+=lowbit(t))
data[t]=data[t]+ad;
}
inline int q(const int&pos){
register ll ret=0;
for(register int t=pos;t;t-=lowbit(t))
ret+=data[t];
return ret;
}
inline void add(const int&l,const int&r,const int&ad){
if(l>r)return;
add(l,ad);add(r+1,-ad);
}
int main(){
int ans=1;
n=qr();
jc[0]=1;
for(register int t=1;t<=n;++t)
jc[t]=1ll*jc[t-1]*t%mod;
for(register int t=1;t<=n;++t)
add(t,t,t);
for(register int t=1,t1;t<=n;++t){
t1=qr();
ans=(ans+1ll*(q(t1)-1)*jc[(n-t)]%mod)%mod;
add(t1+1,n,-1);
}
printf("%d\n",ans);
return 0;
}
原文地址:https://www.cnblogs.com/winlere/p/11198706.html
时间: 2024-11-08 20:47:17