• 2020牛客多校第六场J-Josephus Transform


    题意

    给出一个长度为n的排列,m次操作,每次操作为((k,x)),表示进行x次k-约瑟夫变换

    k-约瑟夫变换即:首先把n个元素排列成环,从第一个元素数k个元素,把这个元素删除,并把它放到新排列(P')中,接着从下一个元素再开始数k个元素,删除,放入,直至没有元素。

    题解

    首先考虑如何求一个 k-约瑟夫变换。注意到每次取出来的数字是剩下所有数字的第几个其实是可以算出来的。不妨设上一个被取出来的数字是当时的第 pos 个(初始设为 1),当前还剩下 cnt 个数字,那么下一个被选出来的数应该是当前剩下的所有数字中的第 $(pos-1+k-1) % cnt + 1 $个,这个可以用线段树或者树状数组来求,所以求一个k-约瑟夫变换的复杂度是 (O(n log n)) 的。

    然后注意到置换满足结合律,所以可以用快速幂来算,复杂度(nlogx)

    代码

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    struct READ {
        inline char read() {
        #ifdef _WIN32
            return getchar();
        #endif
            static const int IN_LEN = 1 << 18 | 1;
            static char buf[IN_LEN], *s, *t;
            return (s == t) && (t = (s = buf) + fread(buf, 1, IN_LEN, stdin)), s == t ? -1 : *s++;
        }
        template <typename _Tp> inline READ & operator >> (_Tp&x) {
            static char c11, boo;
            for(c11 = read(),boo = 0; !isdigit(c11); c11 = read()) {
                if(c11 == -1) return *this;
                boo |= c11 == '-';
            }
            for(x = 0; isdigit(c11); c11 = read()) x = x * 10 + (c11 ^ '0');
            boo && (x = -x);
            return *this;
        }
    } in;
    
    const int N = 1e5 + 50;
    
    #define mid (l+r>>1)
    #define ls (o<<1)
    #define rs (o<<1|1)
    int sum[N << 2];
    void build(int o, int l, int r) {
        if (l == r) { sum[o] = 1; return; }
        build(ls, l, mid); build(rs, mid + 1, r);
        sum[o] = sum[ls] + sum[rs];
    }
    void update(int o, int l, int r, int x, int v) {
        if (l == r) { sum[o] += v; return; }
        if (x <= mid) update(ls, l, mid, x, v);
        else update(rs, mid + 1, r, x, v);
        sum[o] = sum[ls] + sum[rs];
    }
    int query(int o, int l, int r, int v) {
        if (l == r) { return l; }
        if (sum[ls] >= v) return query(ls, l, mid, v);
        else return query(rs, mid + 1, r, v - sum[ls]);
    }
    
    int a[N];
    int n;
    void cals(int k) {
        build(1, 1, n);
        int pos = 1;
        for (int i = 1; i <= n; i++) {
            pos = (pos - 1 + k - 1) % (n - i + 1) + 1;
            a[i] = query(1, 1, n, pos);
            update(1, 1, n, a[i], -1);
        }
    }
    int ans[N];
    int base[N];
    int tmp[N];
    void getAns(int x) {
        for (int i = 1; i <= n; i++) base[i] = a[i];
        while (x) {
            if (x & 1) {
                for (int i = 1; i <= n; i++) tmp[i] = ans[i];
                for (int i = 1; i <= n; i++) ans[i] = tmp[base[i]];
            }
            for (int i = 1; i <= n; i++) tmp[i] = base[i];
            for (int i = 1; i <= n; i++) base[i] = tmp[base[i]];
            x >>= 1;
        }
        
    }
    int main() {
        int m; in >> n >> m;
        for (int i = 1; i <= n; i++) ans[i] = i;
        while (m--) {
            int k, x;
            in >> k >> x;
            cals(k);
            getAns(x);  
        }
        for (int i = 1; i <= n; i++) printf("%d%c", ans[i], i == n ? '
    ' : ' ');
        return 0;
    }
    
    
  • 相关阅读:
    SQL复制表
    文件流 修改二进制文件
    C#代码开启或关闭window service
    程序员之间的相处
    .NET实现图片下载(后台)
    当要存入数据的数据为null时 必须转换成DBNull.Value
    Maven第三篇【Maven术语、pom.xml介绍】
    Maven第二篇【Idea下使用Maven】
    Maven第一篇【介绍、安装、结构目录】
    SSM整合开发
  • 原文地址:https://www.cnblogs.com/artoriax/p/13596657.html
Copyright © 2020-2023  润新知