• Helvetic Coding Contest 2017 online mirror A&B&C. Heidi and Library


    A. Heidi and Library (easy)
    time limit per test
    2 seconds
    memory limit per test
    256 megabytes
    input
    standard input
    output
    standard output

    Your search for Heidi is over – you finally found her at a library, dressed up as a human. In fact, she has spent so much time there that she now runs the place! Her job is to buy books and keep them at the library so that people can borrow and read them. There are ndifferent books, numbered 1 through n.

    We will look at the library's operation during n consecutive days. Heidi knows in advance that on the i-th day (1 ≤ i ≤ n) precisely one person will come to the library, request to borrow the book ai, read it in a few hours, and return the book later on the same day.

    Heidi desperately wants to please all her guests, so she will make sure to always have the book ai available in the library on the i-th day. During the night before the i-th day, she has the option of going to the bookstore (which operates at nights to avoid competition with the library) and buying any book for the price of 1 CHF. Of course, if she already has a book at the library, she does not need to buy it again. Initially, the library contains no books.

    There is a problem, though. The capacity of the library is k – this means that at any time, there can be at most k books at the library. If buying a new book would cause Heidi to have more than k books, she must first get rid of some book that she already has, in order to make room for the new book. If she later needs a book that she got rid of, she will need to buy that book again.

    You are given k and the sequence of requests for books a1, a2, ..., an. What is the minimum cost (in CHF) of buying new books to satisfy all the requests?

    Input

    The first line of input will contain two integers n and k (1 ≤ n, k ≤ 80). The second line will contain n integers a1, a2, ..., an (1 ≤ ai ≤ n) – the sequence of book requests.

    Output

    On a single line print the minimum cost of buying books at the store so as to satisfy all requests.

    Examples
    input
    4 80
    1 2 2 1
    output
    2
    input
    4 1
    1 2 2 1
    output
    3
    input
    4 2
    1 2 3 1
    output
    3
    Note

    In the first test case, Heidi is able to keep all books forever. Therefore, she only needs to buy the book 1 before the first day and the book 2 before the second day.

    In the second test case, she can only keep one book at a time. Therefore she will need to buy new books on the first, second and fourth day.

    In the third test case, before buying book 3 on the third day, she must decide which of the books 1 and 2 she should get rid of. Of course, she should keep the book 1, which will be requested on the fourth day.

    题目大意:有一家图书馆,有k个位置放书,有n天每天一个客人来看书,你必须保证客人来看书的时候图书馆里有他要的书,如果图书管理本来有他要的书就不用买,否则要花1元买这本书。图书馆里同时储存的书不能超过k本,求满足所有客人的最小花费

    Eazy:n,k<=80

    事实上你想不到正解,这个Eazy也很难做

    一眼看不出做法,不妨先去看看Medium的数据范围

    Medium:其他条件不变,n,k<=400,000

    哦,nlogn之类的

    但是也不太知道怎么做,想了一下,遇到新书,格子没满肯定是直接买新的,格子满了的话,不妨丢掉下一次出现最晚的一本,自己想不出反例,写了一发交上去A了

    具体实现用个vector维护出现位置,平衡树维护一下最大值就好了

    我的treap写的真难看

      1 #include <iostream>
      2 #include <cstdlib>
      3 #include <cstdio>
      4 #include <algorithm>
      5 #include <string>
      6 #include <cstring>
      7 #include <cmath>
      8 #include <map>
      9 #include <stack>
     10 #include <set>
     11 #include <vector>
     12 #include <queue>
     13 #include <time.h>
     14 #define eps 1e-7
     15 #define INF 0x3f3f3f3f
     16 #define MOD 1000000007
     17 #define rep0(j,n) for(int j=0;j<n;++j)
     18 #define rep1(j,n) for(int j=1;j<=n;++j)
     19 #define pb push_back
     20 #define set0(n) memset(n,0,sizeof(n))
     21 #define ll long long
     22 #define ull unsigned long long
     23 #define iter(i,v) for(edge *i=head[v];i;i=i->nxt)
     24 #define max(a,b) (a>b?a:b)
     25 #define min(a,b) (a<b?a:b)
     26 #define print_runtime printf("Running time:%.3lfs
    ",double(clock())/1000.0)
     27 #define TO(j) printf(#j": %d
    ",j);
     28 //#define OJ
     29 using namespace std;
     30 const int MAXINT = 400010;
     31 const int MAXNODE = 100010;
     32 const int MAXEDGE = 2 * MAXNODE;
     33 char BUF, *buf;
     34 int read() {
     35     char c = getchar(); int f = 1, x = 0;
     36     while (!isdigit(c)) { if (c == '-') f = -1; c = getchar(); }
     37     while (isdigit(c)) { x = x * 10 + c - '0'; c = getchar(); }
     38     return f*x;
     39 }
     40 char get_ch() {
     41     char c = getchar();
     42     while (!isalpha(c)) c = getchar();
     43     return c;
     44 }
     45 //------------------- Head Files ----------------------//
     46 struct info {
     47     int v, p;
     48     info() {}
     49     info(int _v, int _p) :v(_v), p(_p) {}
     50 };
     51 info add(info a, info b) {
     52     return a.p>b.p ? a : b;
     53 }
     54 struct node {
     55     int key;
     56     info mx, p;
     57     node *fa, *c[2];
     58     int checkfa() {
     59         if (this == fa->c[0]) return 0;
     60         else return 1;
     61     }
     62     void pushup() {
     63         mx = add(add(p, c[0]->mx), c[1]->mx);
     64     }
     65 };
     66 struct treap {
     67     node mp[MAXINT * 2], nil;
     68     node *root, *NIL;
     69     int cnt;
     70     treap() {
     71         NIL = &nil;
     72         NIL->fa = NIL->c[0] = NIL->c[1] = NIL;
     73         NIL->mx = NIL->p = info(-1, -1);
     74         NIL->key = -1;
     75         root = NIL;
     76     }
     77     node *newnode(info v, node *fa) {
     78         node *p = &mp[cnt++];
     79         p->mx = p->p = v;
     80         p->fa = fa;
     81         p->c[0] = p->c[1] = NIL;
     82         p->key = rand();
     83         return p;
     84     }
     85     void rotate(node *p, int d) {
     86         node *pfa = p->fa;
     87         p->fa = pfa->fa;
     88         p->fa->c[pfa->checkfa()] = p;
     89         pfa->fa = p;
     90         pfa->c[d ^ 1] = p->c[d];
     91         pfa->c[d ^ 1]->fa = pfa;
     92         p->c[d] = pfa;
     93         if (root == pfa) root = p;
     94         pfa->pushup();
     95     }
     96     void insert(info v) {
     97         node *p = root,*pfa;
     98         if (p == NIL) { root = newnode(v, NIL); return; }
     99         while (p!=NIL) {
    100             pfa = p;
    101             if (p->p.v>v.v) p = p->c[0];
    102             else p = p->c[1];
    103         }
    104         if (pfa->p.v>v.v) pfa->c[0] = newnode(v, pfa), p = pfa->c[0];
    105         else pfa->c[1] = newnode(v, pfa), p = pfa->c[1];
    106         while (p->key<p->fa->key) rotate(p, p->checkfa() ^ 1);
    107         while (p != NIL) {
    108             p->pushup();
    109             p = p->fa;
    110         }
    111     }
    112     void del(int v) {
    113         node *p = root;
    114         while (p->p.v != v) {
    115             if (p->p.v>v) p = p->c[0];
    116             if (p->p.v<v) p = p->c[1];
    117         }
    118         if (p == root) {
    119             if (p->c[0] == NIL) root = p->c[1];
    120             else if (p->c[1] == NIL) root = p->c[0];
    121             else if (p->c[0]->key>p->c[1]->key) {
    122                 root = p->c[1];
    123             }
    124             else {
    125                 root = p->c[0];
    126             }
    127         }
    128         while (p->c[0] != NIL&&p->c[1] != NIL) {
    129             if (p->c[0]->key>p->c[1]->key) {
    130                 rotate(p->c[1], 0);
    131             }
    132             else {
    133                 rotate(p->c[0], 1);
    134             }
    135         }
    136         if (p->c[0] == NIL&&p->c[1] == NIL) {
    137             p->fa->c[p->checkfa()] = NIL;
    138         }
    139         else if (p->c[0] == NIL) {
    140             p->fa->c[p->checkfa()] = p->c[1];
    141             p->c[1]->fa = p->fa;
    142         }
    143         else {
    144             p->fa->c[p->checkfa()] = p->c[0];
    145             p->c[0]->fa = p->fa;
    146         }
    147         
    148         while (p != NIL) {
    149             p->pushup();
    150             p = p->fa;
    151         }
    152     }
    153     info getmx() {
    154         return root->mx;
    155     }
    156 }tp;
    157 int a[MAXINT], n, k;
    158 int v[MAXINT], c[MAXINT];
    159 vector<int> pos[MAXINT];
    160 void get_input();
    161 void work();
    162 int main() {
    163     srand(559320414);
    164     get_input();
    165     work();
    166     return 0;
    167 }
    168 void work() {
    169     int num = 0, sum = 0;
    170     for (int i = 0; i<n; i++) {
    171         c[a[i]]++;
    172         if (v[a[i]]) {
    173             tp.del(a[i]);
    174             tp.insert(info(a[i], pos[a[i]][c[a[i]]]));
    175             continue;
    176         }
    177         sum++;
    178         if (num<k) {
    179             num++;
    180             tp.insert(info(a[i], pos[a[i]][c[a[i]]]));
    181             v[a[i]] = 1;
    182         }
    183         else {
    184             info ans = tp.getmx();
    185             v[ans.v] = 0;
    186             tp.del(ans.v);
    187             tp.insert(info(a[i], pos[a[i]][c[a[i]]]));
    188             v[a[i]] = 1;
    189         }
    190     }
    191     printf("%d
    ", sum);
    192 }
    193 void get_input() {
    194     n = read(); k = read();
    195     rep0(i, n) a[i] = read(), pos[a[i]].push_back(i);
    196     rep1(i, n) pos[i].push_back(n + i);
    197 }

    Hard:书有不同的费用,n,k<=80

    这个数据范围,费用流吧

    各种东西网上套也没想出来怎么建模

    看了题解,给这个思路跪了

    每一天i拆成两个点2i,2i+1

    SS---(1,第i天所需要的书的费用)-->2i--(1,M(非常小的负数))--->2i+1---(1,0)--->TT

    然后对于每个2i+1,向它后面的每一天的2j连边,边权为(1,0)如果a[i]==a[j],(1,c[a[j]]) otherwise

    进行k次负增广(如果增广使答案更大就拒绝接受),最终的费用+n*M就是答案

    这个图看上去让人莫名其妙,但似乎感觉很厉害

    他为什么对呢?

    显然所有(1,M)的边都会被经过,相当于满足了所有客人的需求

    那么我们增广k次,在图里剩下的就是k条路径

    我们单独考虑每个书架,如果把一个客人分配给一个书架,这个书架的书可以有两个来源:

    1、之前从来没有过书,新了买一本

    2、从以前继承一本,可能不好用,丢掉新买了一本,也可能直接就能用

    是不是有点清楚了

    1就是 SS---(1,第i天所需要的书的费用)-->2i的边

    2就是 2i+1,向它后面的每一天的2j连边,边权为(1,0)如果a[i]==a[j],(1,c[a[j]]) otherwise 的边

    网络中的每一条路径都是一个书架里的书变化的过程

      1 #include <iostream>
      2 #include <cstdlib>
      3 #include <cstdio>
      4 #include <algorithm>
      5 #include <string>
      6 #include <cstring>
      7 #include <cmath>
      8 #include <map>
      9 #include <stack>
     10 #include <set>
     11 #include <vector>
     12 #include <queue>
     13 #include <time.h>
     14 #define eps 1e-7
     15 #define INF 0x3f3f3f3f
     16 #define MOD 1000000007
     17 #define rep0(j,n) for(int j=0;j<n;++j)
     18 #define rep1(j,n) for(int j=1;j<=n;++j)
     19 #define pb push_back
     20 #define set0(n) memset(n,0,sizeof(n))
     21 #define ll long long
     22 #define ull unsigned long long
     23 #define iter(i,v) for(edge *i=head[v];i;i=i->nxt)
     24 #define max(a,b) (a>b?a:b)
     25 #define min(a,b) (a<b?a:b)
     26 #define print_runtime printf("Running time:%.3lfs
    ",double(clock())/1000.0)
     27 #define TO(j) printf(#j": %d
    ",j);
     28 //#define OJ
     29 using namespace std;
     30 const int MAXINT = 85;
     31 const int MAXNODE = 200;
     32 const int MAXEDGE = 20000;
     33 char BUF, *buf;
     34 int read() {
     35     char c = getchar(); int f = 1, x = 0;
     36     while (!isdigit(c)) { if (c == '-') f = -1; c = getchar(); }
     37     while (isdigit(c)) { x = x * 10 + c - '0'; c = getchar(); }
     38     return f * x;
     39 }
     40 char get_ch() {
     41     char c = getchar();
     42     while (!isalpha(c)) c = getchar();
     43     return c;
     44 }
     45 //------------------- Head Files ----------------------//
     46 int cnt, q[MAXNODE * MAXNODE], inq[MAXNODE], SS = MAXNODE - 2, TT = MAXNODE - 1, n, a[MAXINT], c[MAXINT], k;
     47 ll dis[MAXNODE];
     48 struct edge {
     49     int u, v, c, cost;
     50     edge *nxt;
     51     edge(int _u, int _v, int _c, int _cost, edge *_nxt) : u(_u), v(_v), c(_c), cost(_cost), nxt(_nxt) {}
     52     edge() {}
     53 } mp[MAXEDGE], *head[MAXNODE], *from[MAXNODE];
     54 void addedge(int u, int v, int c, int cost) {
     55     mp[cnt] = edge(u, v, c, cost, head[u]);
     56     head[u] = &mp[cnt++];
     57     mp[cnt] = edge(v, u, 0, -cost, head[v]);
     58     head[v] = &mp[cnt++];
     59 }
     60 edge* rev(edge *e) {
     61     return &mp[(e - mp) ^ 1];
     62 }
     63 int spfa(int ss, int tt) {
     64     memset(dis, INF, sizeof(dis));
     65     int *h, *t;
     66     h = t = q;
     67     dis[*t++ = ss] = 0;
     68     while (h != t) {
     69         int p = *h++;
     70         inq[p] = 0;
     71         iter(i, p) {
     72             if (i->c && dis[i->v] > dis[p] + i->cost) {
     73                 dis[i->v] = dis[p] + i->cost;
     74                 from[i->v] = i;
     75                 if (!inq[i->v]) {
     76                     *t++ = i->v;
     77                     inq[i->v] = 1;
     78                 }
     79             }
     80         }
     81     }
     82     return dis[tt] != 0x3f3f3f3f3f3f3f3f;
     83 }
     84 ll extend(int ss, int tt) {
     85     int p = tt, f = INF;
     86     ll cost = 0;
     87     while (p != ss) {
     88         f = min(f, from[p]->c);
     89         cost += from[p]->cost;
     90         p = from[p]->u;
     91     }
     92     p = tt;
     93     while (p != ss) {
     94         from[p]->c -= f;
     95         rev(from[p])->c += f;
     96         p = from[p]->u;
     97     }
     98     return cost*f;
     99 }
    100 ll minflow(int ss, int tt) {
    101     ll ans = 0x3f3f3f3fll * n;
    102     rep0(i, k) {
    103         if (!spfa(ss, tt)) break;
    104         if (dis[TT] >= 0) break;
    105         ans += extend(ss, tt);
    106     }
    107     return ans;
    108 }
    109 void get_input();
    110 void work();
    111 int main() {
    112     get_input();
    113     work();
    114     return 0;
    115 }
    116 void work() {
    117     rep0(i, n) {
    118         addedge(SS, i * 2, 1, c[a[i]]);
    119         addedge(i * 2 + 1, TT, 1, 0);
    120         addedge(i * 2, i * 2 + 1, 1, -INF);
    121     }
    122     rep0(i, n) {
    123         for (int j = i + 1; j<n; j++) {
    124             if (a[i] == a[j]) addedge(i * 2 + 1, j * 2, 1, 0);
    125             else addedge(i * 2 + 1, j * 2, 1, c[a[j]]);
    126         }
    127     }
    128     printf("%lld
    ", minflow(SS, TT));
    129 }
    130 void get_input() {
    131     n = read(); k = read();
    132     rep0(i, n) a[i] = read();
    133     rep1(i, n) c[i] = read();
    134 }
  • 相关阅读:
    WSGIRequest对象 和querydict对象
    限制请求method及页面重定向
    ORM模型里连接数据库常用方法和QuerySet API
    orm模型(关于时区时间)
    spring mvc 前后端数据交互方式(整理)
    java 国际化(转载)
    spring 基础学习笔记
    (转载)java nio 原理解析
    collection 所有集合的接口。
    java.lang.String类
  • 原文地址:https://www.cnblogs.com/LoveYayoi/p/6937907.html
Copyright © 2020-2023  润新知