CF1443E

//CF1443 E
/*
 算法:康托展开
 给定一个全排列,求它是第几小的全排列。
 如 4 2 1 3。
 解:
 int k=0;
 对于 4 它后面有三个数比他小:  k+=3 * (3!)     比它小的个数 * 排列数目,因为若前面的数保持不懂,仅仅统计当前数和它后面的数,1***,2***,3***均比它小共3 * (3!)种排列
 对于 2 它后面有一个数比他小:  k+=1 * (2!)     比它小的个数 * 排列数目,因为若前面的数保持不懂,仅仅统计当前数和它后面的数,41**          均比它小共1 * (2!)种排列
 对于 1 它后面有零个数比他小:  k+=0 * (1!)
 故答案为 20.
 求长度为n的第k小的全排列的多少?
 例:长度为4 第17小的全排列个数
 对于第一个数, 17/(3!)=2;故有1个数比第一个数小,第一个数为3
 17--> 5;
 对于第二个数, 5/(2!)=2;故有2个数比第二个数小,第一个数为4
 5-->1 ;
 对于第三个数, 1/(1!)=0;故有1个数比第三个数小,第一个数为2
 1-->0;
 答案为3 4 2 1
 对于本题,全排列的增量不会超过2e10;那么排列的变化范围不会超过后15个数.那么我只需要对后15个数进行处理
 技巧:若n不足15令n+=15
 */
#include <bits/stdc++.h>
#define inf 2333333333333333
#define p(a) putchar(a)
#define For(i,a,b) for(long long i=a;i<=b;++i)
using namespace std;
const long long maxn=2e5+100;
void in(long long &x){
    long long y=1;char c=getchar();x=0;
    while(c<'0'||c>'9'){if(c=='-')y=-1;c=getchar();}
    while(c<='9'&&c>='0'){ x=(x<<1)+(x<<3)+c-'0';c=getchar();}
    x*=y;
}
void o(long long x){
    if(x<0){p('-');x=-x;}
    if(x>9)o(x/10);
    p(x%10+'0');
}
long long n,q;
long long base[30];
long long a[maxn],sum[maxn];
long long nowk=0;
void init(){
    for(long long i=1;i<=18;i++)base[i]=1;
    for(long long i=1;i<=18;i++){
        for(long long j=1;j<=i;j++)base[i]*=j;
    }
    base[0]=1;
}
void push(long long x){
    nowk+=x;
    vector<long long>num;
    for(long long i=1;i<=15;i++){
        num.push_back(i);
    }
    long long head=n-15;
    long long nowkk=nowk;
    for(long long i=1;i<=15;i++){
        long long j=nowkk/base[15-i];
        nowkk-=j*base[15-i];
        a[head+i]=num[j]+n-15;
        sum[head+i]=sum[head+i-1]+a[head+i];
        num.erase(num.begin()+j,num.begin()+j+1);
    }
}
signed main(){
    init();
    long long op,x,y;
    in(n);in(q);
    long long del=0,up=0;
    for(long long i=1;i<=n+15;i++){
        a[i]=i;
        sum[i]=sum[i-1]+a[i];
    }
    if(n<15){
        del=15;
        up=15;
        n+=15;
    }
    while(q--){
        in(op);
        if(op==1){
            in(x),in(y);
            o(sum[y+up]-sum[x-1+up]-(y-x+1)*del);putchar('\n');
        }
        if(op==2){
            in(x);
            push(x);
        }

    }

    return 0;
}
posted @ 2020-11-05 18:44  yesuweiYYYY  阅读(96)  评论(0编辑  收藏  举报