zoukankan      html  css  js  c++  java
  • ZOJ Bizarre Routine 2013杭州网赛B题

    题目意思:

      给定n, expect, a, b 要求你构造一组array[],存放一个1..n的排列,使的下面的程序能输出YES

      题目所示代码:

        

     1 bool less_than(x, y) {
     2     T++;
     3     return x < y;
     4 }
     5 void work(array[], l, r) {
     6     if (l >= r) return;
     7     swap(array[(l * A + r * B) / (A + B)], array[r]);
     8     int index = l;
     9     for (i = l; i < r; i++)
    10         if (less_than(array[i], array[r]))
    11             swap(array[index++], array[i]);
    12     swap(array[r], array[index]);
    13     work(array, l, index - 1);
    14     work(array, index + 1, r);
    15 }
    16 void main() {
    17     T = 0;
    18     Input(n, expect, A, B, array[]);
    19     work(array, 0, n - 1);
    20     if (T == expect)
    21         Output("YES");
    22     else
    23         Output("NO");
    24 }
    sort

      壕无疑问这是一个快排!

    n个数排列,T的上限是sigma(1..n-1) = n*(n-1)/2

    而下限则可以通过递推得到

      mi[x] = 0                        for x =0, 1

      mi[x] = x-1 + min(mi[i] + mi[x-i-1])  (0 <=i < x)    for x > 1

    当然根据经验得到,i应该是取x/2的时候最好,跑了一下,mi数组也确实没变。。当然跑n^2的应该时间也够。

    而且实际上 mi[i] + mi[x-i-1] 在i = 0..x/2呈现非递增的性质,解法用到了这个性质。

    当expext在上下限之间的时候,可以通过递归构造

    void work(int l, int r, int c)

    构造区间[l,r] 使得这个区间的T = c

    显然这个区间要消耗r - l次

    设对这个区间的第一次排序后中间数在m位置,还要消耗区间[l,m - 1], [m+1, r]

    当m = l .. (l+r)/2   (Ps: 当 m > (l+r)/2时 和<= (l+r)/2的情况是等价的)

    假如[l,m - 1], [m+1, r]均取最小值,则数值呈现非递减

    假如[l,m - 1], [m+1, r]均取最大值,则数值呈现非递减

    由于这个区间一定存在m符合条件,那么取第一个使得区间消耗最小值mi(l,m - 1) + mi(m+1, r) <= c - (r-l) 的必然符合要求(Ps: 把最小值和最大值在纸上画一下函数就明了)

    让左区间取消耗最小值, 然后递归构造

    work(l,m-1,mi[l-m]) work(m1,r,c - (r-l) - mi[l-m])

    我们希望区间[l, r]第一次sort后,p[l..r] = [ p[l..m-1], m ,p[m+1..r] ]

    那么,通过给定的a, b计算得到m原本的下标,手动回滚他程序中的两次swap。

    构造完毕,代码如下:

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <iostream>
     4 #include <algorithm>
     5 using namespace std;
     6 const int N = 10005;
     7 int a,b,p[N];
     8 int mi[N];
     9 inline bool can(int l,int r,int c){
    10     int n = r-l+1;
    11     return c>=mi[n] && c<=n*(n-1)/2;
    12 }
    13 inline void mysort(int l,int m,int r,int id){
    14     p[m] = m;
    15     swap(p[m],p[r]);
    16     swap(p[r],p[id]);
    17 }
    18 void work(int l,int r,int c){
    19     if(l>r) return;
    20     if(l == r){
    21         p[l] = l;
    22         return;
    23     }
    24     int lt = l,rt = (l+r)/2+1, m;
    25     c -= r-l;
    26     while(lt<rt){
    27         m = (lt + rt)>>1;
    28         if(mi[m-l]+mi[r-m] > c) lt = m + 1;
    29         else rt = m;
    30     }
    31     m = lt;
    32     work(l,m-1,mi[m-l]);
    33     work(m+1,r,c-mi[m-l]);
    34     mysort(l,m,r,(l*a + r*b)/(a+b));
    35 }
    36 int n,m;
    37 int main(){
    38     //freopen("in.txt", "r", stdin);
    39     for(int i=2;i<N;i++){
    40         int x = i/2, y = i-x-1;
    41         mi[i] = mi[x]+mi[y]+i-1;
    42     }
    43     //for(int i=0;i<=20;i++)cout<<i<<" "<<mi[i]<<endl;
    44     while(~scanf("%d%d%d%d",&n,&m,&a,&b)){
    45         if(!can(0,n-1,m)){
    46             puts("NOWAY");
    47             continue;
    48         }
    49         work(0,n-1,m);
    50         for(int i=0;i<n;i++) printf(i==n-1?"%d
    ":"%d ",p[i]+1);
    51     }
    52     return 0;
    53 }
  • 相关阅读:
    问题6-10
    7.19 1
    经济学人常见词汇清单
    英语广播原声听力100篇MP3及听力原文
    6.30.2018
    6.26
    6.26
    6.26
    6.25
    6.25
  • 原文地址:https://www.cnblogs.com/hundundm/p/3334045.html
Copyright © 2011-2022 走看看