题目地址
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;
}
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 }
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;
}
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;
}
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;
}
K题:
求吹起最小的宽度,吹灭蛋糕上所有的蜡烛,用旋转卡壳做出凸包上每个点到另一线的距离的最小值即可
来源:oschina
链接:https://my.oschina.net/u/4367417/blog/3857926