ACM-ICPC SouthWestern Europe Regional Contest 2017题解

题目地址 
http://codeforces.com/gym/101635/

A 题:

计算两个数组元素之间最有可能的差值,注意数据全部非法时的情况

#include<bits/stdc++.h>
using namespace std;
const int  maxn = 2005;
int a[maxn], b[maxn];
int main() {
    int n, m;
    scanf("%d%d", &n, &m);
    unordered_map<int, int> mp;
    for (int i = 0; i < n; ++i) {
        scanf("%d", a + i);
    }
    for (int i = 0; i < m; ++i) {
        scanf("%d", b + i);
        for (int j = 0; j < n; ++j) {
            if (a[j] > b[i])
                break;
            ++mp[b[i] - a[j]];
        }
    }
    int max_num = 0, max_cnt = 0;
    for (auto i : mp) {
        if (max_cnt < i.second || max_cnt == i.second && i.first < max_num) {
            max_cnt = i.second;
            max_num = i.first;
        }
    }
    printf("%d\n", max_num);
    return 0;
}
View Code

B 题:

C题:

用1*2 或者 1 * 1的矩形块覆盖n * m的矩形,求出所有可能的摆放方式总数(mod 1e9),通过状压DP计算n = 1 ~ 8条件下的递推式f(n),根据递推式运用矩阵快速幂计算出F(n)的值

D题: 

E题:

给出一个菜谱的有向无环图,有每种菜的花费以及这种菜所依赖的菜的花费和价值,要求最终的菜单中每种菜只能出现一次,问在花费不超过B的前提下,价值和最大。
一种菜的合成受限于另一种菜,容易想到拓扑排序,根据拓扑排序的性质,可以得到每种菜最小的合成代价,然后01背包即可

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int maxn = 1e6 + 7;
 4 typedef long long ll;
 5 const int inf = 0x3f3f3f3f;
 6 char s1[maxn][25];
 7 char s2[maxn][25];
 8 char s3[maxn][25];
 9 int c[maxn];
10 int v[maxn];
11 int cc[maxn];
12 int vv[maxn];
13 int in[maxn];
14 int sta[maxn];
15 map<string, int>mp;
16 vector<pair<int, int> >a[maxn];
17 int ID;
18 int B, n;
19 bool e[maxn];
20 ll dp[maxn];
21 
22 int getid(char s[]) {
23     if (!mp.count(s)) {
24         mp[s] = ++ID;
25         a[ID].clear();
26         cc[ID] = inf;
27         vv[ID] = -inf;
28         in[ID] = 0;
29     }
30     return mp[s];
31 }
32 
33 int main() {
34     while (~scanf("%d%d", &B, &n)) {
35         mp.clear();
36         ID = 0;
37         for (int i = 1; i <= n; i++) {
38             scanf("%s%s%s%d%d", s1[i], s2[i], s3[i], &c[i], &v[i]);
39             int z = getid(s1[i]);
40             int x = getid(s2[i]);
41             int y = getid(s3[i]);
42             ++in[z];
43             a[x].push_back({ y,i });
44             a[y].push_back({ x,i });
45             e[i] = 0;
46         }
47         int top = 0;
48         for (int i = 1; i <= ID; i++) {
49             if (in[i] == 0) {
50                 sta[++top] = i;
51                 cc[i] = vv[i] = 0;
52             }
53         }
54         while (top) {
55             int x = sta[top--];
56             for (auto it : a[x]) {
57                 int y = it.first;
58                 int o = it.second;
59                 if (!e[o] && in[y] == 0) {
60                     e[o] = 1;
61                     int z = mp[s1[o]];
62                     int cost = cc[x] + cc[y] + c[o];
63                     int val = vv[x] + vv[y] + v[o];
64                     if (cost<cc[z] || cost == cc[z] && val>vv[z]) {
65                         cc[z] = cost;
66                         vv[z] = val;
67                     }
68                     if (--in[z] == 0) {
69                         sta[++top] = z;
70                     }
71                 }
72             }
73         }
74         memset(dp, 0, sizeof(dp));
75         dp[0] = 0;
76         for (int i = 1; i <= ID; ++i) {
77             for (int j = B; j >= cc[i]; --j) {
78                 dp[j] = max(dp[j], dp[j - cc[i]] + vv[i]);
79             }
80         }
81         
82         int cost = 0;
83         ll val = 0;
84         for (int i = 1; i <= B; i++) {
85             if (dp[i] > val) {
86                 val = dp[i];
87                 cost = i;
88             }
89         }
90         printf("%lld\n%d\n", val, cost);
91     }
92 }
View Code

F题:

根据 x * y 的和除以w即可得出 L的值

#include<bits/stdc++.h>
using namespace std;

#define ll long long
const int  maxn = 2005;
int main() {
    int w,l;
    while (~scanf("%d", &w)) {
        int n;
        scanf("%d", &n);
        ll sum = 0;
        while (n--) {
            int x, y;
            scanf("%d%d", &x, &y);
            sum += x * y;
        }
        l = sum / w;
        printf("%d\n", l);
    }
    return 0;
}
View Code

G题:

有两种跑匹配的方法,一种是找到有可能对答案做出贡献的快递员到货物的路线建二分图,左边是快递员,右边是货物,权值设置为 len(r->b) - len(c->b),跑一遍最大权值匹配(特判二分图无边的情况,因为最少需要1个快递员运送货物)。
另外一种更简单的方法是是我们建两组点,一组是快递员和n-1个饭店,一组是货物,分别连接快递员到货物,饭店到货物的边,跑一边最大权值匹配。当然这题也可以用最小费用流来做,但需要优化添边的数目以免超时。

#pragma warning(disable:4996)
#include<bits/stdc++.h>
using namespace std;

typedef pair<int, int> pii;
typedef pair<double, int>pdi;
#define ll long long
#define CLR(a,b) memset(a,b,sizeof(a))
#define _for(i, a, b) for (int i = a; i < b; ++i)
const int  mod = (int)1e9 + 7;
const int  maxn = 2005;
const double eps = 1e-8;
const double pi = acos(-1.0);
const int inf = 0x3f3f3f3f;
struct node
{
    int x, y;
};
struct bc_edge {
    int dif, bottle, cart;
    bool operator<(const bc_edge & r) const {
        return dif < r.dif;
    }
};
int cal_dist(node l, node r) {
    return abs(l.x - r.x) + abs(l.y - r.y);
}
node a[maxn], b[maxn];
int dis[maxn];
const int N = 2005;
const int INF = 0x3f3f3f3f;
int nx, ny;//两边的点数
int g[N][N];//二分图描述
int linker[N], lx[N], ly[N];//y中各点匹配状态,x,y中的点标号
int slack[N];
bool visx[N], visy[N];
bool DFS(int x)
{
    visx[x] = true;
    for (int y = 0; y < ny; y++)
    {
        if (visy[y])continue;
        int tmp = lx[x] + ly[y] - g[x][y];
        if (tmp == 0)
        {
            visy[y] = true;
            if (linker[y] == -1 || DFS(linker[y]))
            {
                linker[y] = x;
                return true;
            }
        }
        else if (slack[y] > tmp)
            slack[y] = tmp;
    }
    return false;
}
int KM()
{
    memset(linker, -1, sizeof(linker));
    memset(ly, 0, sizeof(ly));
    for (int i = 0; i < nx; i++)
    {
        lx[i] = -INF;
        for (int j = 0; j < ny; j++)
            if (g[i][j] > lx[i])
                lx[i] = g[i][j];
    }
    for (int x = 0; x < nx; x++)
    {
        for (int i = 0; i < ny; i++)
            slack[i] = INF;
        while (true)
        {
            memset(visx, false, sizeof(visx));
            memset(visy, false, sizeof(visy));
            if (DFS(x))break;
            int d = INF;
            for (int i = 0; i < ny; i++)
                if (!visy[i] && d > slack[i])
                    d = slack[i];
            for (int i = 0; i < nx; i++)
                if (visx[i])
                    lx[i] -= d;
            for (int i = 0; i < ny; i++)
            {
                if (visy[i])ly[i] += d;
                else slack[i] -= d;
            }
        }
    }
    int res = 0;
    for (int i = 0; i < ny; i++)
        if (linker[i] != -1)
            res += g[linker[i]][i];
    return res;
}

int main() {
    int n, m;
    int ans = 0;
    node t;
    scanf("%d%d", &n, &m);
    _for(i, 0, n)
        scanf("%d%d", &a[i].x, &a[i].y);
    _for(i, 0, m)
        scanf("%d%d", &b[i].x, &b[i].y);
    scanf("%d%d", &t.x, &t.y);
    _for(i, 0, n) {
        dis[i] = cal_dist(t, a[i]);
        ans += 2 * dis[i];
    }
    // cout << ans << endl;
    vector<bc_edge> v;
    _for(i, 0, n) {
        _for(j, 0, m) {
            int tmp = cal_dist(a[i], b[j]) - dis[i];
            v.push_back({ tmp, i, j });
        }
    }
    sort(begin(v), end(v));
    for (int i = 0; i < (int)v.size(); ++i) {
        if (v[i].dif < 0) {
            int x = v[i].bottle;
            int y = v[i].cart;
            g[x][y] = -v[i].dif;
        }
        else
            break;
    }
    nx = n + m, ny = n + m;
    int tmp = -v[0].dif;
    if (v[0].dif < 0) {
        tmp = KM();
    }
    printf("%d\n", ans - tmp);
    return 0;
}
View Code

H题:

I题:

J题:

#include<bits/stdc++.h>
using namespace std;

#define ll long long
#define CLR(a,b) memset(a,b,sizeof(a))
const int  mod = 1e9 + 7;
const int  maxn = 2005;
const double eps = 1e-8;
const double pi = acos(-1.0);
const int inf = 0x3f3f3f3f;
ll a[4], b[4], x, y;
int c[4] = { 1,3,2 };
int d[4] = { 2,1,3 };
ll sum[5];
ll chang, kuan;
int n, i, j, f;
int main() {
    chang = 0;
    kuan = 0;
    scanf("%d", &n);
    for (i = 1; i <= n; ++i) {
        scanf("%lld", &x);
        a[i % 3] += x;
    }
    for (i = 1; i <= n; ++i) {
        scanf("%lld", &x);
        b[i % 3] += x;
    }
    printf("%lld %lld %lld\n", b[1] * a[2] + a[1] * b[2] + a[0] * b[0], b[2] * a[2] + a[0] * b[1] + a[1] * b[0], b[1] * a[1] + a[0] * b[2] + a[2] * b[0]);
    return 0;
}
View Code

K题:

求吹起最小的宽度,吹灭蛋糕上所有的蜡烛,用旋转卡壳做出凸包上每个点到另一线的距离的最小值即可

猜你喜欢

转载自www.cnblogs.com/ZKin/p/9507491.html