最新文章

[NOI2008]志愿者招募 题解

[NOI2008]志愿者招募 题解

题目地址:洛谷:【P3980】[NOI2008]志愿者招募 – 洛谷、BZOJ:Problem 1061. — [Noi2008]志愿者招募

题目描述

申奥成功后,布布经过不懈努力,终于成为奥组委下属公司人力资源部门的主管。布布刚上任就遇到了一个难题:为即将启动的奥运新项目招募一批短期志愿者。经过估算,这个项目需要N 天才能完成,其中第i 天至少需要Ai 个人。 布布通过了解得知,一共有M 类志愿者可以招募。其中第i 类可以从第Si 天工作到第Ti 天,招募费用是每人Ci 元。新官上任三把火,为了出色地完成自己的工作,布布希望用尽量少的费用招募足够的志愿者,但这并不是他的特长!于是布布找到了你,希望你帮他设计一种最优的招募方案。

题意简述

有$n$天工作,每一天需要至少$a_i$人,有$m$批人,每一批有无限多人,第$i$批可以从$s_i$天工作到$t_i$天,雇一个人需要$c_i$开销,求开销最小的方案。

输入输出格式

输入格式:
第一行包含两个整数N, M,表示完成项目的天数和可以招募的志愿者的种类。 接下来的一行中包含N 个非负整数,表示每天至少需要的志愿者人数。 接下来的M 行中每行包含三个整数Si, Ti, Ci,含义如上文所述。为了方便起见,我们可以认为每类志愿者的数量都是无限多的。

输出格式:
仅包含一个整数,表示你所设计的最优方案的总费用。

输入输出样例

输入样例#1:

3 3
2 3 4
1 2 2
2 3 5
3 3 2

输出样例#1:

14

说明

1 ≤ N ≤ 1000,1 ≤ M ≤ 10000,题目中其他所涉及的数据均 不超过2^31-1。

题解

考虑最小费用最大流。从第$i$天向第$i+1$天的点建边容量为$INF-a_i$费用$0$,而每一批人从$s_i$向$t_i+1$建边容量为$INF$费用$c_i$,由于保证有解所以一定能跑满$INF$的流,此处即是把每一天对应的流量转到了雇佣的人的边上去了。

代码

// Code by KSkun, 2018/7
#include <cstdio>
#include <cctype>
#include <cstring>

#include <algorithm>
#include <queue>

typedef long long LL;

inline char fgc() {
    static char buf[100000], *p1 = buf, *p2 = buf;
    return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2)
        ? EOF : *p1++;
}

inline LL readint() {
    register LL res = 0, neg = 1; register char c = fgc();
    for(; !isdigit(c); c = fgc()) if(c == '-') neg = -1;
    for(; isdigit(c); c = fgc()) res = res * 10 + c - '0';
    return res * neg;
}

const int MAXN = 1005, INF = 1e9;

int n, m;

struct Edge {
    int to, cap, cost, nxt;
} gra[1000005];
int head[MAXN], tot;

inline void addedge(int u, int v, int cap, int cost) {
    gra[tot] = Edge {v, cap, cost, head[u]}; head[u] = tot++;
    gra[tot] = Edge {u, 0, -cost, head[v]}; head[v] = tot++;
}

int dis[MAXN], f[MAXN], pre[MAXN], pree[MAXN];
bool inque[MAXN];
std::queue<int> que;

inline bool spfa(int s, int t) {
    memset(dis, 0x3f, sizeof(dis));
    memset(f, 0, sizeof(f));
    que.push(s); dis[s] = 0; f[s] = INF; inque[s] = true;
    while(!que.empty()) {
        int u = que.front(); que.pop(); inque[u] = false;
        for(int i = head[u]; ~i; i = gra[i].nxt) {
            int v = gra[i].to;
            if(dis[v] > dis[u] + gra[i].cost && gra[i].cap) {
                dis[v] = dis[u] + gra[i].cost;
                f[v] = std::min(f[u], gra[i].cap); pre[v] = u; pree[v] = i;
                if(!inque[v]) {
                    inque[v] = true; que.push(v);
                }
            }
        }
    }
    return f[t];
}

int flow, cost;

inline void mcmf(int s, int t) {
    while(spfa(s, t)) {
        flow += f[t]; cost += f[t] * dis[t];
        for(int i = t; i != s; i = pre[i]) {
            gra[pree[i]].cap -= f[t];
            gra[pree[i] ^ 1].cap += f[t];
        }
    }
}

int S, T;

int main() {
    memset(head, -1, sizeof(head));
    n = readint(); m = readint(); S = 0; T = n + 1;
    for(int i = 1; i <= n; i++) {
        int t = readint();
        addedge(i, i + 1, INF - t, 0);
    }
    addedge(S, 1, INF, 0);
    for(int i = 1; i <= m; i++) {
        int s = readint(), t = readint(), c = readint();
        addedge(s, t + 1, INF, c);
    }
    mcmf(S, T);
    printf("%d", cost);
    return 0;
}
NOI2018笔试改错

NOI2018笔试改错

LOJ513 「LibreOJ NOI Round #1」笔试

49. NOI 比赛中选手的程序不能用的有:
A. 使用 fork 生成进程
B. __asm__
C. __int128
D. std::map

Output: AB
Expected: ABC
A在题库里写着有,B asm不能用是肯定的,C NOI的机器是32位,没有__int128给你用

UOJ392 【UNR #3】笔试

17. 在 Anjuta 中调试程序,继续执行的快捷键是
A. F9
B. F6
C. F4
D. Reset键

Output: B
Expected: C
Anjuta continue F4,Lazarus run F9,Anjuta step over F6,Lazarus step over F8

30. Linux 中查看当前路径使用的命令是
A. pwd
B. rm -rf /
C. dir
D. ls

Output: D
Expected: A
pwd看路径,ls看文件,ls -a看隐藏文件,ls -l看文件大小

307 【UNR #2】笔试

没错233

212 【UNR #1】笔试

3. 测试点时间限制的含义是指
A. 系统时间
B. 题目允许程序运行所占用的用户时间总和的上限值
C. 题目的所有测试点允许程序运行所占用的用户时间总和的上限值

Output: C
Expected: B
没有“所有测试点”这个条件

[JSOI2009]计数问题 题解

[JSOI2009]计数问题 题解

题目地址:洛谷:【P4054】[JSOI2009]计数问题 – 洛谷、BZOJ:Problem 1452. — [JSOI2009]Count

题目描述

一个n*m的方格,初始时每个格子有一个整数权值。接下来每次有2种操作:

  • 改变一个格子的权值;
  • 求一个子矩阵中某种特定权值出现的个数。

输入输出格式

输入格式:
第一行有两个数N,M。
接下来N行,每行M个数,第i+1行第j个数表示格子(i,j)的初始权值。
接下来输入一个整数Q。
之后Q行,每行描述一个操作。
操作1:“1 x y c”(不含双引号)。表示将格子(x,y)的权值改成c(1<=x<=n,1<=y<=m,1<=c<=100)。
操作2:“2 x1 x2 y1 y2 c”(不含双引号,x1<=x2,y1<=y2)。表示询问所有满足格子颜色为c,且x1<=x<=x2,y1<=y<=y2的格子(x,y)的个数。

输出格式:
对于每个操作2,按照在输入中出现的顺序,依次输出一行一个整数表示所求得的个数。

输入输出样例

输入样例#1:

3 3
1 2 3
3 2 1
2 1 3
3
2 1 2 1 2 1
1 2 3 2
2 2 3 2 3 2

输出样例#1:

1
2

说明

数据规模:
30%的数据,满足:n,m<=30,Q<=50000
100%的数据,满足:n,m<=300,Q<=200000

题解

注意到权值的范围很小,对每个权值开一个二维树状数组即可。二维树状数组可以理解成树状数组套树状数组。
复杂度$O(n \log^2 n)$。

代码

// Code by KSkun, 2018/7
#include <cstdio>
#include <cctype>
#include <cstring>

#include <algorithm>

typedef long long LL;

inline char fgc() {
    static char buf[100000], *p1 = buf, *p2 = buf;
    return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2)
        ? EOF : *p1++;
}

inline LL readint() {
    register LL res = 0, neg = 1; register char c = fgc();
    for(; !isdigit(c); c = fgc()) if(c == '-') neg = -1;
    for(; isdigit(c); c = fgc()) res = (res << 1) + (res << 3) + c - '0';
    return res * neg;
}

const int MAXN = 305;

int n, m, q, tr[105][MAXN][MAXN], a[MAXN][MAXN];

inline int lowbit(int x) {
    return x & -x;
}

inline void add(int x, int y, int w, int v) {
    for(int i = x; i <= n; i += lowbit(i)) {
        for(int j = y; j <= m; j += lowbit(j)) {
            tr[w][i][j] += v;
        }
    }
}

inline int query(int x, int y, int w) {
    int res = 0;
    for(int i = x; i; i -= lowbit(i)) {
        for(int j = y; j; j -= lowbit(j)) {
            res += tr[w][i][j];
        }
    }
    return res;
}

int main() {
    n = readint(); m = readint();
    for(int i = 1; i <= n; i++) {
        for(int j = 1; j <= m; j++) {
            a[i][j] = readint();
            add(i, j, a[i][j], 1);
        }
    }
    q = readint();
    while(q--) {
        int op = readint();
        if(op == 1) {
            int x = readint(), y = readint(), c = readint();
            add(x, y, a[x][y], -1);
            a[x][y] = c;
            add(x, y, a[x][y], 1);
        } else {
            int x1 = readint(), x2 = readint(), y1 = readint(), y2 = readint(), c = readint();
            printf("%d\n", query(x2, y2, c) - query(x1 - 1, y2, c) - query(x2, y1 - 1, c) + query(x1 - 1, y1 - 1, c));
        }
    }
    return 0;
}