zoukankan      html  css  js  c++  java
  • 2016_1_13(3)

    点餐 

     (dinner.cpp/c/pas)  

    【时间】1s

    【问题描述】 

    清儿今天请好朋友们吃饭,一共N个人坐在坐在圆桌旁。

    吃饭的第一步当然是点餐了。服务员拿来了M份菜单。第i个人阅读菜单并点出自己喜欢的菜需要花费时间T[i]

    当一个人点完菜之后,就会把菜单传到他右手边的第一个人。

    M份菜单是同时发出的,每个菜单只能同时被一个人阅读。

    清儿希望知道如何分发菜单,才能让点餐的总时间花费最少呢?

    【输入】  

    输入文件名为dinner.in

    输入第一行是NM,表示人数和菜单数

    输入第二行,N个数,表示每个人点餐所需要的时间。

    【输出】 

    输出文件名为dinner.out

    输出一个整数表示点餐花费的最小时间。

    【输入输出样例】

    #1

    3 2

    1 5 10

    10

    #2

    4 2

    1 2 3 4

    5

    【数据说明】 

    对于20%的数据,有1≤n≤100

    对于60%的数据,有1≤n≤10000

    对于100%的数据,有1≤n≤50000,T[i]<=600

    这道题直接说了吧。我的做法是二分然后n^2 check,当时也想到了用倍增来优化那一个n^2,但是我比较蠢

    只想到了mlogn的做法。然后正解是每次二分到一个ans之后处理出每一个点能到达的最远的点。然后跑一次倍增。

    然后枚举起点,就可以logn check了。

    总复杂度是nlogn^2

     1 #include <cstdio>
     2 #include <iostream>
     3 #include <cstdlib>
     4 #include <iostream>
     5 #include <cstring>
     6 using namespace std;
     7 const int N = 100003;
     8 int n,m,M = 1,cnt = 0;
     9 int a[2*N],l,r,maxna;
    10 int ans = 2000000000;
    11 int anc[2*N][30];
    12 int st[3*N];
    13 inline void prepare(int mid) {
    14     int sum = 0;
    15     int h = 0 ,t = 0;
    16     for(int i = 1 ; i <= n+n ; ++i) {
    17         st[++t] = i;
    18         if(sum + a[i] <= mid) sum += a[i];
    19         else {
    20             do {
    21                 anc[st[++h]][0] = i;
    22                 sum -= a[st[h]];
    23             }while(sum + a[i] > mid);
    24             sum += a[i];
    25         }
    26     }
    27     while(h<t) {
    28         h++;
    29         anc[st[h]][0] = 2*n+1;
    30     }
    31     for(int j = 0 ; j <= cnt ; ++j) anc[2*n+1][j] = 2*n+1;
    32     for(int j = 1 ; j <= cnt ; ++j) {
    33         for(int i = 1 ; i <= 2*n ; ++i) {
    34             anc[i][j] = anc[anc[i][j-1]][j-1];
    35         }
    36     }
    37 }
    38 inline bool check(int mid) {
    39     if(mid < maxna) return false;
    40     prepare(mid);
    41     for(int i = 1 ; i <= n ; ++i) {
    42         int k = m;
    43         int x = i;
    44         for(int j = cnt ; j >= 0 ; --j) {
    45             if((1<<j)<=k) {
    46                 k -= (1<<j);
    47                 x = anc[x][j];
    48             }
    49         }
    50         if(x>=i+n) return true;
    51     }
    52     return false;
    53 }
    54 int main() {
    55     freopen("dinner.in","r",stdin);
    56     freopen("dinner.out","w",stdout);
    57     scanf("%d%d",&n,&m);
    58     while(m>=M) {
    59         M<<=1;
    60         cnt++;
    61     }
    62     cnt--;
    63     for(int i = 1 ; i <= n ; ++i) scanf("%d",&a[i]),r+=a[i],maxna = max(maxna,a[i]),a[i+n] = a[i];
    64     do {
    65         int mid = (l+r)>>1;
    66         if(check(mid)) ans = min(ans,mid) , r = mid;
    67         else l = mid + 1;
    68     }while(l<r);
    69     if(check(l)) ans = min(ans,l);
    70     cout << ans << endl;
    71 }
    View Code
  • 相关阅读:
    《CUDA并行程序设计:GPU编程指南》
    《设计搜索体验:搜索的艺术与科学》
    《iOS应用逆向工程:分析与实战》
    《实战突击:PHP项目开发案例整合(第2版)(含DVD光盘1张)》
    《完美幻灯片设计的黄金法则》
    《Haskell趣学指南》
    《全程软件测试(第2版)》
    【互动出版网】2013双12全场科技类图书6.5折封顶
    【互动出版网】新书五折限量抢——图书超低价
    c# (ENUM)枚举组合类型的谷歌序列化Protobuf
  • 原文地址:https://www.cnblogs.com/registerzxr/p/5127430.html
Copyright © 2011-2022 走看看