zoukankan      html  css  js  c++  java
  • codeforces 1443E-Long Permutation (树状数组 + 康托展开)

    题目链接:https://codeforces.com/problemset/problem/1443/E

    我们发现,排列的排名最多只会是 (10^10),所以最多只会修改 (15) 个位置
    我们记录一下当前的排列排名是多少,然后只需要暴力进行逆康托展开,求出当前排名下的排列,暴力修改即可

    求和用树状数组维护,暴力修改后 (15) 个位置即可

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    #include<cmath>
    #include<stack>
    #include<queue>
    using namespace std;
    typedef long long ll;
    
    const int maxn = 200010;
    
    int n, q; 
    
    ll c[maxn], fac[maxn];
    
    void add(int x, ll k){
    	for(; x <= n ; x += x & (-x)){
    		c[x] += k;
    	} 
    }
    
    ll query(int x){
    	ll res = 0;
    	for(; x ; x -= x & (-x)){
    		res += c[x];
    	}
    	return res;
    }
    
    
    int v[20], a[20], p[maxn];
    
    void change(ll sum){
    	for(int i = 1 ; i <= 15 ; ++i) v[i] = 1;
    	ll tmp = sum;
    	
    	for(int i = 1 ; i <= 15 ; ++i){
    		int t = tmp / fac[15 - i];
    		int cnt = 0;
    		for(int j = 1 ; j <= 15 ; ++j){
    			if(v[j]){
    				if(cnt == t){
    					a[i] = j;
    					v[j] = 0;
    					break;
    				}
    				++cnt;
    			}
    		}
    		tmp %= fac[15 - i];
    	}
    	
    	if(n < 15){
    		int d = 15 - n;
    		for(int i = 1 ; i <= n ; ++i){
    			add(i, -p[i]);
    			p[i] = a[i + d] - d;
    			add(i, p[i]);
    		}
    	} else{
    		int d = n - 15;
    		for(int i = n - 14 ; i <= n ; ++i){
    			add(i, -p[i]);
    			p[i] = a[15 - (n - i)] + d;
    			add(i, p[i]);
    		}
    	}
    }
    
    ll read(){ ll s=0,f=1; char ch=getchar(); while(ch<'0' || ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } while(ch>='0' && ch<='9'){ s=s*10+ch-'0'; ch=getchar(); } return s*f; }
    
    int main(){
    	n = read(), q = read();
    	for(int i = 1 ; i <= n ; ++i) add(i, i);
    	for(int i = 1 ; i <= n ; ++i) p[i] = i;
    	fac[0] = 1;
    	for(int i = 1 ; i <= 15 ; ++i) fac[i] = fac[i - 1] * i;
    	
    	ll ans = 0;
    	int op, x, y;
    	for(int i = 1 ; i <= q ; ++i){
    		op = read();
    		if(op == 1){
    			x = read(), y = read();
    			printf("%lld
    ", query(y) - query(x - 1));
    		} else{
    			x = read();
    			ans += x;
    			change(ans);
    		}
    	}
    	
    	return 0;
    }
    
  • 相关阅读:
    js打开新窗口
    JS普通浏览器页面传参
    MUI之移动APP页面之间传递参数
    flex布局原理
    css3之Tab页面切换
    css之左边竖条的实现方法
    “程序猿”——要理清你的思路!
    win32调试——OutputDebugString
    des加密——补齐
    SVN 过滤文件
  • 原文地址:https://www.cnblogs.com/tuchen/p/14024677.html
Copyright © 2011-2022 走看看