zoukankan      html  css  js  c++  java
  • 康拓展开--P5367 【模板】康托展开

    举个栗子大家应该就能懂了:

    我现在生成了1~5的全排列,求数列5  2  3  1  4是第几个

    5:有四个数比他小,他后面还有4个数,所以他的贡献应该是4*4!

    2:有一个数比他小,他后面还有3个数,所以他的贡献应该是1*3!

    3:有两个数比他小,他后面还有两个数,但是其中2在前面出现过了,所以他的贡献应该是1*2!

    1:有零个数比他小,他后面还有一个数,所以他的贡献应该是0*1!

    4:有三个数比他小,他后面还有0个数,但是1 2 3都在前面出现过,所以他的贡献应该是0*0!

    所以数列5  2  3  1  4的前面有4*4!+1*3!+1*2!+0*1!+0*0!个数列

    它本身就是第4*4!+1*3!+1*2!+0*1!+0*0!+1个数列

    如何知道比他小的数字的个数,和树状数组维护逆序对的原理一样,初始时都为1,如果出现过,就-1,求前缀和

    而阶乘我们可以用秦九韶算法优化,比如上面的式子就=((((4*4+1)*3)+1)*2+0)*1+0*1+1

    代码:

     1 #include <iostream>
     2 #include <algorithm>
     3 #include <cstdio>
     4 using namespace std;
     5 #define int long long
     6 const int maxn=1e6+10,mod=998244353;
     7 int n;
     8 int a[maxn],tmp[maxn],sum[maxn];
     9 void fix(int x,int k){
    10   for (int i = x;i <= n;i+=i&(-i)) sum[i]+=k;
    11 }
    12 int query(int x){
    13   int res=0;
    14   for (int i = x;i >= 1;i-=i&(-i)) res+=sum[i];
    15   return res;
    16 }
    17 signed main(){
    18   scanf ("%lld",&n);
    19   for (int i = 1;i <= n;i++) fix(i,1);
    20   for (int i = 1;i <= n;i++) scanf ("%lld",&a[i]);
    21   for (int i = 1;i <= n;i++){
    22     tmp[i]=query(a[i]-1);
    23     fix(a[i],-1);
    24   }
    25   int ans=tmp[1]*(n-1);
    26   for (int i = 2;i <= n-1;i++){
    27     ans=ans+tmp[i]; ans=ans%mod;
    28     ans=ans*(n-i); ans=ans%mod;
    29   }
    30   ans=ans+1;ans+=ans*tmp[n]*1;ans=ans%mod;
    31   printf("%lld
    ",ans);
    32   return 0;
    33 }
  • 相关阅读:
    cf D. Vessels
    cf C. Hamburgers
    zoj 3758 Singles' Day
    zoj 3777 Problem Arrangement
    zoj 3778 Talented Chef
    hdu 5087 Revenge of LIS II
    zoj 3785 What day is that day?
    zoj 3787 Access System
    判断给定图是否存在合法拓扑排序
    树-堆结构练习——合并果子之哈夫曼树
  • 原文地址:https://www.cnblogs.com/very-beginning/p/13757448.html
Copyright © 2011-2022 走看看