zoukankan      html  css  js  c++  java
  • POJ

    · 对于差分约束,题目要求求什么便设什么,令$Sum[i]$表示由$0 ~ i$的雇佣人数。

    · 要充分利用题目所给条件,令$Have[i]$表示i时刻申报的人数,$Need[i]$表示i时刻需要的人数「结合 “人数” 关键词」。

    此时容易列出两个基本不等式:

        Sum[i] - Sum[i - 1] >= 0;

       Sum[i] - Sum[i - 1] <= Have[i];

    此时发现还有$Need[]$和范围为8个单位长度的区间没有使用,可得:

        Sum[i] - Sum[i - 8] >= Need[i]; (i >= 8)

    那么还有环形无法处理。

    对于环形的处理:

    将整个$24$个单位的区间以当前点为分割点,将大区间分割为$(i - 8 + 24)$ ~ $i$ (环形)以及$i$ ~ $i + 16$,相当于覆盖了整个环形区间。

    相当于是去限制非当前考虑的完整的区间从而达到限制当前因环形而断开的区间。

    所以此时仅需考虑两个区间间的限制即可。

    并且需要一个$Sum[- 1]$。

    答案显然满足单调性,故考虑二分。

    令$mid$表示需要$mid$个服务员。

    则可列方程:

        mid - (Sum[i + 16] - Sum[i]) >= Need[i]; (i < 8)

    即可解答。

    · 代码:

      1 #include <iostream>
      2 #include <cstdio>
      3 #include <cstring>
      4 #include <queue>
      5 
      6 using namespace std;
      7 
      8 const int MAXN = 1000 + 10;
      9 const int MAXM = MAXN * 10;
     10 const int MAXT = 24 + 10;
     11 
     12 struct LinkedForwardStar {
     13     int to;
     14     int w;
     15 
     16     int next;
     17 } ;
     18 
     19 LinkedForwardStar Link[MAXM << 1];
     20 int Head[MAXT]= {0};
     21 int size = 0;
     22 
     23 void Insert (int u, int v, int w) {
     24     Link[++ size].to = v;
     25     Link[size].w = w;
     26     Link[size].next = Head[u];
     27 
     28     Head[u] = size;
     29 }
     30 
     31 int T;
     32 
     33 int N;
     34 
     35 int Have[MAXT];
     36 int Need[MAXN];
     37 
     38 int Dist[MAXT];
     39 int Count[MAXT];
     40 
     41 queue<int> Que;
     42 bool Inque[MAXT];
     43 
     44 bool SPFA (int mid) {
     45     memset (Dist, 0xcf, sizeof (Dist));
     46     memset (Count, 0, sizeof (Count));
     47     memset (Inque, 0, sizeof (Inque));
     48     while (! Que.empty())
     49         Que.pop();
     50 
     51     Que.push(24);
     52     Inque[24] = true;
     53     Dist[24] = 0;
     54 
     55     while (! Que.empty()) {
     56         int u = Que.front();
     57         Que.pop();
     58 
     59         Inque[u] = false;
     60         Count[u] ++;
     61 
     62         if (Count[u] >= 25)
     63             return false;
     64 
     65         for (int i = Head[u]; i; i = Link[i].next) {
     66             int v = Link[i].to, w = Link[i].w;
     67 
     68             if (Dist[u] + w > Dist[v]) {
     69                 Dist[v] = Dist[u] + w;
     70 
     71                 if (! Inque[v]) {
     72                     Que.push(v);
     73                     Inque[v] = true;
     74                 }
     75             }
     76         }
     77     }
     78 
     79     return Dist[23] == mid;
     80 }
     81 
     82 bool Check (int mid) {
     83     memset (Head, 0, sizeof (Head));
     84     size = 0;
     85 
     86     Insert (24, 23, mid);
     87     Insert (24, 0, 0);
     88     Insert (0, 24, - Have[0]);
     89     for (int i = 1; i <= 23; i ++) {
     90         Insert (i - 1, i, 0);
     91         Insert (i, i - 1, - Have[i]);
     92     }
     93     for (int i = 8; i <= 23; i ++)
     94         Insert (i - 8, i, Need[i]);
     95     for (int i = 0; i < 8; i ++)
     96         Insert (i + 16, i, Need[i] - mid);
     97 
     98     return SPFA (mid);
     99 }
    100 
    101 int main () {
    102     scanf ("%d", & T);
    103 
    104     for (int Case = 1; Case <= T; Case ++) {
    105         memset (Have, 0, sizeof (Have));
    106 
    107         for (int i = 0; i <= 23; i ++)
    108             scanf ("%d", & Need[i]);
    109 
    110         scanf ("%d", & N);
    111 
    112         for (int i = 1; i <= N; i ++) {
    113             int start;
    114             scanf ("%d", & start);
    115 
    116             Have[start] ++;
    117         }
    118 
    119         bool flag = false;
    120         int left = 0, right = N;
    121         while (left < right) {
    122             int mid = (left + right) >> 1;
    123 
    124             if (Check (mid)) {
    125                 flag = true;
    126                 right = mid;
    127             }
    128             else
    129                 left = mid + 1;
    130         }
    131 
    132         if (! flag)
    133             puts ("No Solution");
    134         else
    135             printf ("%d
    ", left);
    136     }
    137 
    138     return 0;
    139 }
    140 
    141 /*
    142 1
    143 1 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
    144 5
    145 0
    146 23
    147 22
    148 1
    149 10
    150 */
    View Code
  • 相关阅读:
    基于Token的WEB后台认证机制
    MySQL主键设计
    .NET学习笔记 -- 那堆名词到底是啥(CLR、CLI、CTS、CLS、IL、JIT)
    C#学习笔记 -- Attribute
    Log4Net指南
    Windows进程通信 -- 共享内存(1)
    windows进程通信 -- WM_COPYDATA消息
    C语言再学习之内存对齐
    找工作中……
    做了一个vue的同步tree 的npm组件包
  • 原文地址:https://www.cnblogs.com/Colythme/p/9696565.html
Copyright © 2011-2022 走看看