【题解】康拓展开(养生题)

【题解】康拓展开(养生题)

养生养生

编号 题目 状态 分数 总时间 内存 代码 / 答案文件 提交者 提交时间
#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;
}

posted @ 2019-07-17 08:37  谁是鸽王  阅读(198)  评论(0编辑  收藏  举报