zoukankan      html  css  js  c++  java
  • CEOI 2009 Day1 A

    题目链接

    CEOI 2009 Day1 A - boxes

    题目大意

    交互题。

    一个环上有 (n) 个位置,开始你要放 (frac{n}{4}) 个盒子上去,接下来系统再放 (frac{n}{4}) 个盒子,每次系统给出 (b_i),要求在第 (b_i) 个插入的盒子后面插入一个盒子,由于后面可能没有空,你需要通过若干次调整腾出空来,每次调整可以把一个盒子推到别的地方,但是需要推的路径上没有别的盒子。调整后指定一个在 (b_i) 和下一个盒子之间的位置插入新的盒子。

    要求每次插入盒子前,你做的调整次数 (leq 200)

    (n=20000)

    思路

    首先可以注意到不能有很多的盒子贴在一起,若贴在一起的盒子超过 (400) 个,那么系统要求在中间插一个盒子就完蛋了,于是考虑分组,要求贴在一起的盒子数量不超过定值 (B),总共分 (frac{n}{2B}) 组。

    题目有一个极端情况,即一直在第一个盒子后面插入新盒子,所以要想办法把插在那个组里的盒子分流到其它组中,可以这么做:当一个组盒子数量超过 (B) 时,把边上的一个盒子扔到别的组里,如果那个组也超 (B) 个了,就按照方向继续扔盒子。在组内部从两个方向腾出一个位置总共需要调整 (B) 次,在扔盒子直到遇到第一个放完后不超过 (B) 个的组的过程中总共需要调整 (frac{n}{2B}) 次,所以必然可以选取一个合适的方向使得调整的次数 (leq (B+frac{n}{2B})/2),取 (B=sqrt{frac{n}{2}}=100),则这里可以调整不超过 (100) 次。

    观察调整的变化情况,以向右(顺时针)扔为例,可以发现相当于从当前组到第一个 (leq B) 组之间的组都左移了一格,由于第一个 (leq B) 的那个组左边多了一个盒子,所以只有当前组和右边相邻组之间的间距减小了,现在还剩 (100) 次调整次数,可以将一整个组进行平移,考虑用这个操作使得组与组之间不贴在一起。

    开始的时候我们按照 (50) 个一组,等间距地放在环上,设两组之间空隙的长度为 (a_i),那么我们初始有一个长度为 (m=100)(a_i) 全为 (150) 的的序列 (a),每次有一个 (a_i) 减一,你可以选取一个 (jin[1,m],kinmathbb Z),使得 (a_j+k)(a_{j+1}-k)(下标循环定义)。

    我们每次选取最大的值 (a_i), 将其减小到 (100),然后使 (a_{i-1}) 相应地增加。由于最终空隙数量 (=n/2=100m),所以 (a_igeq 100),此时相当于最大值的位置左移 (1)(a_{i-1}) 上了,可以发现这样一个过程会一直进行,可以发现在 (100) 轮后,所有的 (a_i) 都会被更新一遍,而想要 (a_i)(100) 减少到 (0) 至少需要 (100) 轮,所以可以保证任意时刻 (min{a_i}geq 0),从而这么做是正确的。

    然后就做完了,时间复杂度是 (O(操作数)=O(nsqrt n)) 的。

    可以发现实际上我们一次操作的调整次数上限为 ((B+frac{n}{2B})/2+B=frac{3B}{2}+frac{n}{4B}),根据不等式,当 (B=58) 时操作数上限为 (174) 次,是最优的情况。

    Code

    // https://cses.fi/179/submit/A
    
    #include<iostream>
    #define rep(i,a,b) for(int i = (a); i <= (b); i++)
    #define per(i,b,a) for(int i = (b); i >= (a); i--)
    #define N 20021
    #define M 110
    #define L 100
    using namespace std;
     
    int n, m;
    int a[N], loc[N], cnt, forbid;
    int l[M], r[M], cat[N];
    
    void put(int pos, int c, bool print){ 
        if(print) cout<<"I "<<pos<<endl, cout.flush(); 
        a[pos] = ++cnt, loc[cnt] = pos, cat[cnt] = c;
    }
    void move(int id, int pos, int c){ 
        if(!id) return;
        if(id != forbid) cout<<"M "<<id<<" "<<pos<<endl, cout.flush(); 
        a[loc[id]] = 0, a[pos] = id, loc[id] = pos, cat[id] = c;
    }
    int pre(int i){ return (i+m-2)%m+1; }
    int nxt(int i){ return i%m+1; }
    int bck(int i){ return (i+n-2)%n+1; }
    int frt(int i){ return i%n+1; }
    int dis(int i, int j){ return (j+n-i)%n+1; }
    
    int main(){
        ios::sync_with_stdio(false);
        cin>>n;
        m = n/2/L;
        rep(i,1,m){
            rep(j,1,L/2) put((i-1)*2*L+j, i, 1);
            l[i] = (i-1)*2*L+1, r[i] = (i-1)*2*L+L/2;
        }
        
        rep(_,1,n/4){
            int b; cin>>b;
            int p = loc[b], c = cat[b];
            int ldis = dis(l[c], p), rdis = dis(p, r[c]) - 1;
            for(int i = pre(c); dis(l[i],r[i]) == L; i = pre(i)) ldis++;
            for(int i = nxt(c); dis(l[i],r[i]) == L; i = nxt(i)) rdis++;
    
            forbid = cnt+1;
            if(rdis <= ldis){
                for(int i = r[c]; i != p; i = bck(i)) move(a[i], frt(i), c);
                put(p+1, c, 0), r[c] = frt(r[c]);
                for(int i = c; dis(l[i],r[i]) > L; i = nxt(i))
                    move(a[r[i]], bck(l[nxt(i)]), nxt(i)), r[i] = bck(r[i]), l[nxt(i)] = bck(l[nxt(i)]);
            } else{
                for(int i = l[c]; i != frt(p); i = frt(i)) move(a[i], bck(i), c);
                put(p, c, 0), l[c] = bck(l[c]);
                for(int i = c; dis(l[i],r[i]) > L; i = pre(i))
                    move(a[l[i]], frt(r[pre(i)]), pre(i)), l[i] = frt(l[i]), r[pre(i)] = frt(r[pre(i)]);
            }
    
            int mx = 0, pc = 0;
            rep(i,1,m) if(mx < dis(r[i],l[nxt(i)])-2)
                mx = dis(r[i],l[nxt(i)])-2, pc = i;
            int st = (l[nxt(pc)]+n - L-2) % n + 1;
    
            int i = r[pc], j = st;
            while(i != bck(l[pc])) move(a[i], j, pc), i = bck(i), j = bck(j);
            r[pc] = st, l[pc] = frt(j);
    
            cout<<"I "<<loc[cnt]<<endl;
        }
        return 0;
    }
    
  • 相关阅读:
    vue中element-ui的内置过渡动画
    vue路由自动加载、按组件异步载入vuex以及dll优化
    h5春节小游戏制作
    python脚本通过adb命令安装包
    pipeline
    python闭包与装饰器
    linux-awk
    CSAPP Lab3: The Attack Lab
    CSAPP Lab4 Cache Lab
    HDU. 2243. 考研路茫茫——单词情结(AC自动机 DP 矩阵快速幂)
  • 原文地址:https://www.cnblogs.com/Neal-lee/p/15251751.html
Copyright © 2011-2022 走看看