Codeforces Round #377 (Div. 2) ABCDEF 题解

A. Buy a Shovel

有单价为k的商品和1个r面额的硬币,输出最小的不需要找零的最小购买件数。for就行了。

#include <map>
#include <set>
#include <cmath>
#include <ctime>
#include <queue>
#include <stack>
#include <string>
#include <vector>
#include <cctype>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <algorithm>
using namespace std;
typedef __int64 LL;
typedef pair<int,int> PII;
#define mp make_pair
#define pb push_back
#define FIN freopen("in.txt", "r", stdin)
#define FOUT freopen("out.txt", "w", stdout)
#define lson l, mid, cur << 1
#define rson mid + 1, r, cur << 1 | 1
#define lowbit(x) ((x)&(-(x)))
#define bitcnt(x) __builtin_popcount(x)
#define bitcntll(x) __builtin_popcountll(x)
#define debug puts("-------------");
//#pragma comment(linker, "/STACK:1024000000,1024000000")
const int INF = 0x3f3f3f3f;
const LL INFLL = 0x3f3f3f3f3f3f3f3fLL;
const double eps = 1e-8;
const int MOD = 1e9 + 7;
const int MAXN = 2e2 + 50;
const int MAXM = 2e4 + 50;

int k, r;

int main() {
#ifdef LOCAL_NORTH
//    FIN;
#endif // LOCAL_NORTH
    while (~scanf("%d%d", &k, &r)) {
        int ans = 0;
        for (int i = 1; ; i++) {
            if (k * i % 10 == r || k * i % 10 == 0) {
                printf("%d\n", i);
                break;
            }
        }
    }
#ifdef LOCAL_NORTH
    cout << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC * 1000 << " ms." << endl;
#endif // LOCAL_NORTH
    return 0;
}

B. Cormen — The Best Friend Of a Man

增大一个序列中的某些项,使得增加后的序列的相连两项和为k。输出增加的值的和。

贪心着搞就行了,第一天不变,之后的每一项都根据前一项来确定增加多少,然后输出和。

#include <map>
#include <set>
#include <cmath>
#include <ctime>
#include <queue>
#include <stack>
#include <string>
#include <vector>
#include <cctype>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <algorithm>
using namespace std;
typedef __int64 LL;
typedef pair<int,int> PII;
#define mp make_pair
#define pb push_back
#define FIN freopen("in.txt", "r", stdin)
#define FOUT freopen("out.txt", "w", stdout)
#define lson l, mid, cur << 1
#define rson mid + 1, r, cur << 1 | 1
#define lowbit(x) ((x)&(-(x)))
#define bitcnt(x) __builtin_popcount(x)
#define bitcntll(x) __builtin_popcountll(x)
#define debug puts("-------------");
//#pragma comment(linker, "/STACK:1024000000,1024000000")
const int INF = 0x3f3f3f3f;
const LL INFLL = 0x3f3f3f3f3f3f3f3fLL;
const double eps = 1e-8;
const int MOD = 1e9 + 7;
const int MAXN = 5e2 + 50;
const int MAXM = 2e4 + 50;

int n, k, a[MAXN];

int main() {
#ifdef LOCAL_NORTH
    FIN;
#endif // LOCAL_NORTH
    while (~scanf("%d%d", &n, &k)) {
        for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
        int ans = 0;
        for (int i = 2; i <= n; i++) {
            if (a[i] < k - a[i - 1]) {
                ans += k - a[i - 1] - a[i];
                a[i] = k - a[i - 1];
            }
        }
        printf("%d\n", ans);
        for (int i = 1; i <= n; i++) printf("%d%c", a[i], " \n"[i == n]);
    }
#ifdef LOCAL_NORTH
    cout << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC * 1000 << " ms." << endl;
#endif // LOCAL_NORTH
    return 0;
}

C. Sanatorium

给定b,d,s分别为一个人吃早餐,中餐(可以这么理解)和晚餐的次数,输出这个人最少有几顿饭没吃。note:这个人可能在一天中的任意时间到达,比如晚饭之前,这样他就吃上晚饭,所以0 0 1这组数据的答案是0。

首先假设在早饭之前到达,取b,d,s中最大的,作为最后一天,然后就可以计算一个答案。

然后s--,也就是假设晚饭之前到达,可以计算出一个答案。

最后d--,假设中饭之前到达,计算出一个答案。

然后3个答案取最小值。

#include <map>
#include <set>
#include <cmath>
#include <ctime>
#include <queue>
#include <stack>
#include <string>
#include <vector>
#include <cctype>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <algorithm>
using namespace std;
typedef __int64 LL;
typedef pair<int,int> PII;
#define mp make_pair
#define pb push_back
#define FIN freopen("in.txt", "r", stdin)
#define FOUT freopen("out.txt", "w", stdout)
#define lson l, mid, cur << 1
#define rson mid + 1, r, cur << 1 | 1
#define lowbit(x) ((x)&(-(x)))
#define bitcnt(x) __builtin_popcount(x)
#define bitcntll(x) __builtin_popcountll(x)
#define debug puts("-------------");
//#pragma comment(linker, "/STACK:1024000000,1024000000")
const int INF = 0x3f3f3f3f;
const LL INFLL = 0x3f3f3f3f3f3f3f3fLL;
const double eps = 1e-8;
const int MOD = 1e9 + 7;
const int MAXN = 5e2 + 50;
const int MAXM = 2e4 + 50;

LL b, d, s;

int main() {
#ifdef LOCAL_NORTH
    FIN;
#endif // LOCAL_NORTH
    while (~scanf("%I64d%I64d%I64d", &b, &d, &s)) {
        LL maxx = max(b, max(d, s));
        LL ans = 0;
        ans += max(maxx - 1 - b, 0LL);
        ans += max(maxx - 1 - d, 0LL);
        ans += max(maxx - 1 - s, 0LL);
        if (s == maxx) ans += (s == b ? 0 : 1) + (s == d ? 0 : 1);
        else if (d == maxx) ans += (b == d ? 0 : 1);
        s--;
        LL maxx1 = max(b, max(d, s));
        LL ans1 = 0;
        ans1 += max(maxx1 - 1 - b, 0LL);
        ans1 += max(maxx1 - 1 - d, 0LL);
        ans1 += max(maxx1 - 1 - s, 0LL);
        if (s == maxx1) ans1 += (s == b ? 0 : 1) + (s == d ? 0 : 1);
        else if (d == maxx1) ans1 += (b == d ? 0 : 1);
        d--;
        LL maxx2 = max(b, max(d, s));
        LL ans2 = 0;
        ans2 += max(maxx2 - 1 - b, 0LL);
        ans2 += max(maxx2 - 1 - d, 0LL);
        ans2 += max(maxx2 - 1 - s, 0LL);
        if (s == maxx2) ans2 += (s == b ? 0 : 1) + (s == d ? 0 : 1);
        else if (d == maxx2) ans2 += (b == d ? 0 : 1);
        printf("%I64d\n", min(ans, min(ans1, ans2)));
    }
#ifdef LOCAL_NORTH
    cout << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC * 1000 << " ms." << endl;
#endif // LOCAL_NORTH
    return 0;
}

D. Exams

有n(n <= 2e5)天和m个科目,要在n天内把m个科目全部考完,每天可以 复习某一科或者进行某一科的考试。

输入d[i],代表第i天只能考科目d[i],d[i]==0代表当天不能考试。

再输入m门科目的复习时间,在科目i考试之前必须花费a[i]复习科目i。

最后输出考完所有科目最短时间,考不完则输出-1。


首先记录一下m门科目的考试时间,然后二分答案,每次检查能否在mid天之前(含mid)完成。

通过二分考试时间数组来找到m门科目在mid之前的最晚考试时间。

定义一个变量来记录可用的复习时间。把科目按照时间从小到大排序开始枚举,每次检查re是否大于等于a[第i个科目的id] + 1,小于0即false,否则re加上从当前科目的考试时间到下一个科目的考试时间。能遍历到m同时re>=0即为true。

#include <map>
#include <set>
#include <cmath>
#include <ctime>
#include <queue>
#include <stack>
#include <string>
#include <vector>
#include <cctype>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <algorithm>
using namespace std;
typedef __int64 LL;
typedef pair<int,int> PII;
#define mp make_pair
#define pb push_back
#define FIN freopen("in.txt", "r", stdin)
#define FOUT freopen("out.txt", "w", stdout)
#define lson l, mid, cur << 1
#define rson mid + 1, r, cur << 1 | 1
#define lowbit(x) ((x)&(-(x)))
#define bitcnt(x) __builtin_popcount(x)
#define bitcntll(x) __builtin_popcountll(x)
#define debug puts("-------------");
//#pragma comment(linker, "/STACK:1024000000,1024000000")
const int INF = 0x3f3f3f3f;
const LL INFLL = 0x3f3f3f3f3f3f3f3fLL;
const double eps = 1e-8;
const int MOD = 1e9 + 7;
const int MAXN = 1e5 + 50;
const int MAXM = 2e4 + 50;

int n, m, d[MAXN], a[MAXN];
vector<int> app[MAXN];

struct node{
    int id, index;
    bool operator < (const node& _) const {return index < _.index;}
}lastApp[MAXN];
bool judge(int len) {
    for (int i = 1; i <= m; i++) {
        lastApp[i].index = -1;
        vector<int>::iterator p = upper_bound(app[i].begin(), app[i].end(), len);
        if (p != app[i].begin())
            lastApp[i].index = *(p - 1);
        lastApp[i].id = i;
    }
    sort(lastApp + 1, lastApp + m + 1);
    int re = lastApp[1].index;
    for (int i = 1; i < m; i++) {
        re -= a[lastApp[i].id] + 1;
        if (re < 0) return false;
        re += lastApp[i + 1].index - lastApp[i].index;
    }
    re -= a[lastApp[m].id] + 1;
    if (re < 0) return false;
    return true;
}

int main() {
#ifdef LOCAL_NORTH
    FIN;
#endif // LOCAL_NORTH
    while (~scanf("%d%d", &n, &m)) {
        for (int i = 1; i <= n; i++) app[i].clear();
        for (int i = 1; i <= n; i++) {
            scanf("%d", &d[i]);
            app[d[i]].pb(i);
        }
        for (int i = 1; i <= m; i++) scanf("%d", &a[i]);
        int l = 1, h = n, ans = -1;
        while (l <= h) {
            int mid = (l + h) / 2;
            if (judge(mid)) {
                ans = mid;
                h = mid - 1;
            }
            else l = mid + 1;
        }
        printf("%d\n", ans);
    }
#ifdef LOCAL_NORTH
    cout << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC * 1000 << " ms." << endl;
#endif // LOCAL_NORTH
    return 0;
}

E. Sockets

n台电脑,m个插头,每个插头可以连接一台电脑,当电脑电压等于插头电压时,电脑可以工作。给出电脑工作电压,插头的电压,现在可以把插头电压变为(原电压+1)/2,。求最多能工作的电脑数c以及使c台电脑工作的最小变换次数。

把电脑安装power排序。定义一个pos指针,指向当前电脑。把每个插头的id、power以及每个插头的变换次数放到优先队列中。

每次取power最大,变换次数最小的插头检查与电脑pos的电压比较,大于pos电压就加一除二重新入队,等于就pop并且pos--,小于重新入队且pos--。

中途记录一下匹配的id。然后就可以输出答案了。

#include <map>
#include <set>
#include <cmath>
#include <ctime>
#include <queue>
#include <stack>
#include <string>
#include <vector>
#include <cctype>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
#define mp make_pair
#define pb push_back
#define FIN freopen("in.txt", "r", stdin)
#define FOUT freopen("out.txt", "w", stdout)
#define lson l, mid, cur << 1
#define rson mid + 1, r, cur << 1 | 1
#define lowbit(x) ((x)&(-(x)))
#define bitcnt(x) __builtin_popcount(x)
#define bitcntll(x) __builtin_popcountll(x)
#define debug puts("-------------");
//#pragma comment(linker, "/STACK:1024000000,1024000000")
const int INF = 0x3f3f3f3f;
const LL INFLL = 0x3f3f3f3f3f3f3f3fLL;
const double eps = 1e-8;
const int MOD = 1e9 + 7;
const int MAXN = 2e5 + 50;
const int MAXM = 1e4 + 50;

int n, m;
int match[MAXN][2], cnt[MAXN];
struct node{
    int id, power;
    node() {}
    node(int _id, int _power) {
        id = _id;
        power = _power;
    }
    bool operator < (const node& _) const {
        if (power != _.power)
            return power < _.power;
        return cnt[id] > cnt[_.id];
    }
}p[MAXN], s[MAXN];

int main() {
#ifdef LOCAL_NORTH
    FIN;
#endif // LOCAL_NORTH
    while (~scanf("%d%d", &n, &m)) {
        memset(match, 0, sizeof(match));
        memset(cnt, 0, sizeof(cnt));
        for (int i = 1; i <= n; i++) {
            scanf("%d", &p[i].power);
            p[i].id = i;
        }
        sort(p + 1, p + 1 + n);
        priority_queue<node> q;
        for (int i = 1; i <= m; i++) {
            scanf("%d", &s[i].power);
            s[i].id = i;
            q.push(node(s[i].id, s[i].power));
        }
        int ans1 = 0, ans2 = 0, pos = n;
        while (!q.empty() && pos >= 1) {
            node t = q.top();
            q.pop();
            if (t.power > p[pos].power) {
                if (t.power != 1) {
                    t.power = (t.power + 1) / 2;
                    cnt[t.id]++;
                    q.push(t);
                }
            } else {
                if (t.power == p[pos].power) {
                    ans1++;
                    ans2 += cnt[t.id];
                    match[p[pos].id][0] = t.id;
                    match[t.id][1] = 1;
                } else q.push(t);
                pos--;
            }
        }
        printf("%d %d\n", ans1, ans2);
        for (int i = 1; i <= m; i++)
            printf("%d%c", match[i][1] == 0 ? 0 : cnt[i], " \n"[i == m]);
        for (int i = 1; i <= n; i++)
            printf("%d%c", match[i][0], " \n"[i == n]);
    }
#ifdef LOCAL_NORTH
    cout << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC * 1000 << " ms." << endl;
#endif // LOCAL_NORTH
    return 0;
}

F. Tourist Reform

给出一个n个点,m条边的连通无重边的无向图。现在把无向变有向,使得r[i](r[i]表示从i出发能够达到的点的个数,包含到达自身)的最小值最大。

首先可以知道的是,限制变换后的有向图的the minimum of r[i]的大小的一定是原无向图中的桥。因为去掉原图中的桥的时候,原图会被分为两个不连通的子图,所以在变换后,必定会有一个子图无法到达另一个子图。所以瓶颈是原图中的桥。进而就可以得出:变换后的有向图中的桥都必须背向顶点数最多的双连通分量。这样操作就会使只有一个双连通分量被孤立,同时被孤立的点的数目是最多的。

然后考虑把原图中的桥断开后,原图就变成了若干个双连通分量,下一步就是把它们变为强连通分量,使得连通分量内部两两可达。

所以具体过程就是:

(1)求原图中的桥

(2)去掉图中的桥,把双连通分量变为强连通分量。每次从双连通分量中的任意一点出发开始dfs,每走一条边就记录答案,通过vis来判断是否已经走过该点,同时不能走桥。每进行完一次dfs,就更新一下顶点数最多的双连通分量,start为该连通分量中的任意一点。

(3)从start出发开始dfs,遇到桥就记录一下答案,注意要反向记录。

#include <map>
#include <set>
#include <cmath>
#include <ctime>
#include <queue>
#include <stack>
#include <string>
#include <vector>
#include <cctype>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <algorithm>
using namespace std;
typedef __int64 LL;
typedef pair<int, int> PII;
#define mp make_pair
#define pb push_back
#define FIN freopen("in.txt", "r", stdin)
#define FOUT freopen("out.txt", "w", stdout)
#define lson l, mid, cur << 1
#define rson mid + 1, r, cur << 1 | 1
#define lowbit(x) ((x)&(-(x)))
#define bitcnt(x) __builtin_popcount(x)
#define bitcntll(x) __builtin_popcountll(x)
#define debug puts("-------------");
//#pragma comment(linker, "/STACK:1024000000,1024000000")
const int INF = 0x3f3f3f3f;
const LL INFLL = 0x3f3f3f3f3f3f3f3fLL;
const double eps = 1e-8;
const int MOD = 1e9 + 7;
const int MAXN = 4e5 + 50;
const int MAXM = 4e5 + 50;

int n, m, ans[MAXN][2];
struct Edge {
    int from, to, nxt, d;
    bool cut;
} E[MAXM << 1];
int Head[MAXN], tot;
int Low[MAXN], DFN[MAXN], Stack[MAXN];
int Index, top;
bool Instack[MAXN];
bool cut[MAXN];
int add_block[MAXN];
int bridge;
void edge_add(int u, int v) {
    E[tot].from = u; E[tot].to = v; E[tot].nxt = Head[u]; E[tot].d = 0; E[tot].cut = false; Head[u] = tot++;
    E[tot].from = v; E[tot].to = u; E[tot].nxt = Head[v]; E[tot].d = 0; E[tot].cut = false; Head[v] = tot++;
}

void Tarjan(int u, int pre) {
    int v;
    Low[u] = DFN[u] = ++Index;
    Stack[top++] = u;
    Instack[u] = true;
    int son = 0;
    for(int i = Head[u]; i != -1; i = E[i].nxt) {
        v = E[i].to;
        if(v == pre)continue;
        if( !DFN[v] ) {
            son++;
            Tarjan(v, u);
            if(Low[u] > Low[v])Low[u] = Low[v];
            if(Low[v] > DFN[u]) {
                bridge++;
                E[i].cut = true;
                E[i ^ 1].cut = true;
            }
            if(u != pre && Low[v] >= DFN[u]) {
                cut[u] = true;
                add_block[u]++;
            }
        } else if( Low[u] > DFN[v])
            Low[u] = DFN[v];
    }
    if(u == pre && son > 1)cut[u] = true;
    if(u == pre)add_block[u] = son - 1;
    Instack[u] = false;
    top--;
}

bool vis[MAXN];
int dcc;
void dfs1(int u, int pre) {
    dcc++;
    vis[u] = true;
    for (int i = Head[u]; ~i; i = E[i].nxt) {
        int v = E[i].to;
        if (E[i].cut) continue;
        ans[i >> 1][0] = u;
        ans[i >> 1][1] = v;
        if (!vis[v]) dfs1(v, u);
    }
}
void dfs2(int u) {
    vis[u] = true;
    for (int i = Head[u]; ~i; i = E[i].nxt) {
        int v = E[i].to;
        if (!vis[v]) {
            if (E[i].cut) {
                ans[i >> 1][0] = v;
                ans[i >> 1][1] = u;
            }
            dfs2(v);
        }
    }
}

void init() {
    memset(DFN, 0, sizeof(DFN));
    memset(Instack, false, sizeof(Instack));
    memset(add_block, 0, sizeof(add_block));
    memset(cut, false, sizeof(cut));
    Index = top = 0;
    bridge = 0;
    tot = 0;
    memset(Head, -1, sizeof(Head));
    memset(vis, false, sizeof(vis));
}

int main() {
#ifdef LOCAL_NORTH
    FIN;
#endif // LOCAL_NORTH
    while (~scanf("%d%d", &n, &m)) {
        init();
        for (int i = 0; i < m; i++) {
            int u, v;
            scanf("%d%d", &u, &v);
            edge_add(u, v);
        }
        for (int i = 1; i <= n; i++)
            if (!DFN[i])
                Tarjan(i, i);
        int start, maxx = 0;
        for (int i = 1; i <= n; i++) {
            if (vis[i]) continue;
            dcc = 0;
            dfs1(i, i);
            if (dcc > maxx) {
                maxx = dcc;
                start = i;
            }
        }
        memset(vis, false, sizeof(vis));
        dfs2(start);
        printf("%d\n", maxx);
        for (int i = 0; i < m; i++) {
            printf("%d %d\n", ans[i][0], ans[i][1]);
        }
    }
#ifdef LOCAL_NORTH
    cout << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC * 1000 << " ms." << endl;
#endif // LOCAL_NORTH
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值