zoukankan      html  css  js  c++  java
  • 第17届科大讯飞杯 I-纸牌 (循环节 思维)

    题目:传送门

    题意

     思路

    对于 k <= n - 1 的情况,我们可以将全部的牌隔一个位存起来,也就是起初的时候,第 i 张牌,放在 b[ 2 * i - 1 ] 的位置。每次操作将第 i 张牌放到第 (i - 1) % (n - 1) + 2 = i + 1 的位置的下一位,即放到 b[ 2 * (i + 1) ] 的位置。因为在 i 之前的操作,都不会将牌放到 2 * (i + 1) 之后,所以,第 i 次操作,可以保证在 2 * (i + 1) 前恰好有 i 张牌,所以这么做是可行的。

    对于 k > n - 1的情况,假设 n - 1 次操作后的编号为 a[ i ],则 2(n - 1) 次操作后的位置为 a[ a[ i ] ],以此类推,那我们可以对数组 a 找出所有的环,令 Z = k / (n - 1),即这个环需要转 Z 步,令 cnt 为环的长度,那么转了 cnt 步就等于没转,所以只需转 Z % cnt 步即可。剩下的 k % (n - 1) 直接按 k <= n - 1 做一次就好了。

    #include <bits/stdc++.h>
    #define LL long long
    #define ULL unsigned long long
    #define UI unsigned int
    #define mem(i, j) memset(i, j, sizeof(i))
    #define rep(i, j, k) for(int i = j; i <= k; i++)
    #define dep(i, j, k) for(int i = k; i >= j; i--)
    #define pb push_back
    #define make make_pair
    #define INF 0x3f3f3f3f
    #define inf LLONG_MAX
    #define PI acos(-1)
    #define fir first
    #define sec second
    #define lb(x) ((x) & (-(x)))
    #define dbg(x) cout<<#x<<" = "<<x<<endl;
    using namespace std;
    
    const int N = 1e6 + 5;
    
    int a[N], b[N << 1];
    
    bool vis[N];
    
    void getnx(int n, int k) {
    
        rep(i, 1, n) {
    
            b[2 * i] = 0;
    
            b[2 * i - 1] = a[i];
    
        }
    
        int now = 1;
    
        rep(i, 1, k) {
    
            while(!b[now]) now++;
    
            swap(b[now], b[(i + 1) * 2]);
    
        }
    
        now = 0;
    
        rep(i, 1, 2 * n) {
    
            if(b[i]) a[++now] = b[i];
    
        }
    
    }
    
    void getloop(int n, LL k) { /// 找循环
    
        rep(i, 1, n) {
    
            if(vis[i]) continue;
    
            int cnt = 0, now = i;
    
            while(!vis[now]) { /// 找循环长度
    
                vis[now] = 1;
    
                b[++cnt] = now;
    
                now = a[now];
    
            }
    
            int need = k % cnt;
    
            b[0] = b[cnt];
    
            rep(i, 1, cnt) { /// 环转动 need 步
    
                a[b[i]] = b[(i + need) % cnt];
    
            }
    
        }
    
    }
    
    void solve() {
    
        int n;
    
        LL k;
    
        scanf("%d", &n);
    
        scanf("%lld", &k);
    
        rep(i, 1, n) a[i] = i;
    
        getnx(n, n - 1);
    
        getloop(n, k / (n - 1));
    
        getnx(n, k % (n - 1));
    
        rep(i, 1, n) printf("%d ", a[i]);
    
    }
    
    int main() {
    
    //    int _; scanf("%d", &_);
    //    while(_--) solve();
    
        solve();
    
        return 0;
    }
  • 相关阅读:
    java.lang.Class
    公司面试题目之取出数据库中重复的记录
    常用的linux基础命令
    算法练习4冒泡排序java版
    算法练习1桶排序java版
    算法练习2斐波那契数列java版
    算法练习3水仙花数java版
    mysql查询语句复习小结
    linux设置开机自动进入命令模式
    JSP九大内置对象和四个作用域
  • 原文地址:https://www.cnblogs.com/Willems/p/12874876.html
Copyright © 2011-2022 走看看