文章目录
2020牛客暑期多校训练营(第八场)题解及补题
比赛过程
这场打的罚时太高了,一开始没有想到签到题就需要用算法,一直在想贪心策略,冷静下来想用并查集和拓扑排序做了,K题一开始思路没有问题,但是有一些小细节错误和没有及时注意到暴longlong了,导致wa的太多,顺便学习了__int128的用法。G题数据量看似 O ( n 3 ) O(n^3) O(n3) 不可行,其实跑不满,直接莽就可以了,不过在比赛的时候还是把 o ( n 2 ) o(n^2) o(n2) 的做法写出来了。
题解
(没过/没补的题空着不管,过了/补了的题目写题意/解法/代码)
(如果要写数学式子用 LaTeX \LaTeX LATEX,比如表达式 x 2 + 2 x + 1 x^2+2x+1 x2+2x+1)
A
题意
有
n
n
n 个球员,
m
m
m 个粉丝。给出每个球员的所有粉丝。
如果一个人是这个球员的粉丝,那么这个人喜欢看这个球员。
如果A和B都喜欢看同一个球员,那么如果B喜欢看的球员A也喜欢看。
问最少需要多少球员才能让每一个粉丝都愿意看,即至少有一个喜欢看的球员入选。有
q
q
q 次粉丝关系的修改,修改完回答询问。
解法
事实上这题就是求连通块的个数,如果有球迷的度为
0
0
0,那么答案为-1,否则答案为连通块个数-孤立球员个数。使用可撤销并查集来维护。记录每一条边的存在时间,使用线段树来维护边的存在时间。
可撤销并查集不可以路径压缩,所以需要按秩合并,用栈来保存,撤销的时候还原祖先结点。
代码
#pragma region
#include <algorithm>
#include <cmath>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <unordered_map>
#include <vector>
using namespace std;
typedef long long ll;
#define tr t[root]
#define lson t[root << 1]
#define rson t[root << 1 | 1]
#define rep(i, a, n) for (int i = a; i <= n; ++i)
#define per(i, a, n) for (int i = n; i >= a; --i)
namespace fastIO {
#define BUF_SIZE 100000
#define OUT_SIZE 100000
//fread->R
bool IOerror = 0;
//inline char nc(){char ch=getchar();if(ch==-1)IOerror=1;return ch;}
inline char nc() {
static char buf[BUF_SIZE], *p1 = buf + BUF_SIZE, *pend = buf + BUF_SIZE;
if (p1 == pend) {
p1 = buf;
pend = buf + fread(buf, 1, BUF_SIZE, stdin);
if (pend == p1) {
IOerror = 1;
return -1;
}
}
return *p1++;
}
inline bool blank(char ch) { return ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t'; }
template <class T>
inline bool R(T &x) {
bool sign = 0;
char ch = nc();
x = 0;
for (; blank(ch); ch = nc())
;
if (IOerror) return false;
if (ch == '-') sign = 1, ch = nc();
for (; ch >= '0' && ch <= '9'; ch = nc()) x = x * 10 + ch - '0';
if (sign) x = -x;
return true;
}
inline bool R(double &x) {
bool sign = 0;
char ch = nc();
x = 0;
for (; blank(ch); ch = nc())
;
if (IOerror) return false;
if (ch == '-') sign = 1, ch = nc();
for (; ch >= '0' && ch <= '9'; ch = nc()) x = x * 10 + ch - '0';
if (ch == '.') {
double tmp = 1;
ch = nc();
for (; ch >= '0' && ch <= '9'; ch = nc())
tmp /= 10.0, x += tmp * (ch - '0');
}
if (sign)
x = -x;
return true;
}
inline bool R(char *s) {
char ch = nc();
for (; blank(ch); ch = nc())
;
if (IOerror)
return false;
for (; !blank(ch) && !IOerror; ch = nc())
*s++ = ch;
*s = 0;
return true;
}
inline bool R(char &c) {
c = nc();
if (IOerror) {
c = -1;
return false;
}
return true;
}
template <class T, class... U>
bool R(T &h, U &... t) { return R(h) && R(t...); }
#undef OUT_SIZE
#undef BUF_SIZE
}; // namespace fastIO
using namespace fastIO;
template <class T>
void _W(const T &x) { cout << x; }
void _W(const int &x) { printf("%d", x); }
void _W(const int64_t &x) { printf("%lld", x); }
void _W(const double &x) { printf("%.16f", x); }
void _W(const char &x) { putchar(x); }
void _W(const char *x) { printf("%s", x); }
template <class T, class U>
void _W(const pair<T, U> &x) { _W(x.F), putchar(' '), _W(x.S); }
template <class T>
void _W(const vector<T> &x) {
for (auto i = x.begin(); i != x.end(); _W(*i++))
if (i != x.cbegin()) putchar(' ');
}
void W() {}
template <class T, class... U>
void W(const T &head, const U &... tail) { _W(head), putchar(sizeof...(tail) ? ' ' : '\n'), W(tail...); }
#pragma endregion
const int maxn = 4e5 + 10;
map<int, int> mp[maxn];
int n, m, q, cnt, cnta, cntb;
struct con {
int a, b;
};
struct recv {
int a, asz, b, bsz;
int cnt, cnta, cntb;
};
struct node {
int l, r;
vector<con> e;
vector<recv> rec;
} t[maxn << 2];
int f[maxn], sz[maxn], ans[maxn];
inline void build(int root, int l, int r) {
tr.l = l, tr.r = r, tr.e.clear(), tr.rec.clear();
if (l == r) return;
int mid = (l + r) >> 1;
build(root << 1, l, mid);
build(root << 1 | 1, mid + 1, r);
}
inline void add(int root, int l, int r, con d) {
if (l <= tr.l && tr.r <= r) {
tr.e.push_back(d);
return;
}
int mid = (tr.l + tr.r) >> 1;
if (l <= mid) add(root << 1, l, r, d);
if (r > mid) add(root << 1 | 1, l, r, d);
}
inline int find(int x) { return f[x] == x ? x : find(f[x]); }
inline void solve(int root) {
int aa, bb, len = 0;
recv tmp;
for (con d : t[root].e) {
aa = find(d.a);
bb = find(d.b);
if (aa == bb) continue;
tmp.cnt = cnt;
tmp.cnta = cnta;
tmp.cntb = cntb;
--cnt;
if (sz[aa] == 1) --cnta;
if (sz[bb] == 1) --cntb;
if (sz[aa] < sz[bb]) swap(aa, bb);
tmp.a = aa;
tmp.asz = sz[aa];
tmp.b = bb;
tmp.bsz = sz[bb];
sz[aa] += sz[bb];
f[bb] = aa;
t[root].rec.push_back(tmp);
++len;
}
if (t[root].l == t[root].r) {
if (cntb != 0)
ans[t[root].l] = -1;
else
ans[t[root].l] = cnt - cnta;
} else {
solve(root << 1);
solve(root << 1 | 1);
}
for (int i = len - 1; i >= 0; i--) {
tmp = t[root].rec[i];
cnt = tmp.cnt;
cnta = tmp.cnta;
cntb = tmp.cntb;
f[tmp.a] = tmp.a;
f[tmp.b] = tmp.b;
sz[tmp.a] = tmp.asz;
sz[tmp.b] = tmp.bsz;
}
}
int main() {
R(n, m, q);
int a, b;
build(1, 1, q + 1);
rep(i, 1, n) {
int k;
R(k);
while (k--) {
R(b);
mp[i][b] = 1;
}
}
rep(i, 2, q + 1) {
R(b, a);
if (mp[a][b] == 0)
mp[a][b] = i;
else {
add(1, mp[a][b], i - 1, con{a, b + n});
mp[a][b] = 0;
}
}
rep(i, 1, n) for (auto d : mp[i]) if (d.second != 0)
add(1, d.second, q + 1, con{i, d.first + n});
rep(i, 1, n + m) {
f[i] = i;
sz[i] = 1;
}
cnt = n + m, cnta = n, cntb = m;
solve(1);
rep(i, 2, q + 1) W(ans[i]);
}
B
题意
解法
代码
//将内容替换成代码
C
题意
解法
代码
//将内容替换成代码
D
题意
解法
代码
//将内容替换成代码
E
题意
定义
n
n
n的拆分为
n
=
a
[
1
]
+
a
[
2
]
+
.
.
.
+
a
[
m
]
n=a[1]+a[2]+...+a[m]
n=a[1]+a[2]+...+a[m],并且满足以下几个条件:
1、
a
[
i
]
≤
a
[
i
+
1
]
≤
a
[
i
]
+
1
,
i
∈
[
1
,
m
]
a[i]\leq a[i+1]\leq a[i]+1,i\in[1,m]
a[i]≤a[i+1]≤a[i]+1,i∈[1,m]
2、
1
≤
a
[
i
]
≤
n
,
i
∈
[
1
,
m
]
1\leq a[i]\leq n,i\in[1,m]
1≤a[i]≤n,i∈[1,m]
3、
a
[
m
]
=
a
[
1
]
+
2
a[m]=a[1]+2
a[m]=a[1]+2
设
f
(
n
)
f(n)
f(n)为满足条件下
n
n
n的拆分有多少种,给出
t
t
t组查询,每组给出一对
[
l
,
r
]
[l,r]
[l,r],求
∑
i
=
l
r
f
(
i
)
\sum_{i=l}^{r}f(i)
∑i=lrf(i)
解法
预处理 f ( n ) f(n) f(n)的前缀和。通过取 a [ 1 ] a[1] a[1]和 m m m遍历所有数,通过规律二阶差分处理得到 f ( n ) f(n) f(n),再遍历求前缀和。
代码
#pragma GCC optimize("O3")
#pragma G++ optimize("O3")
#include <bits/stdc++.h>
//#include <ext/pb_ds/assoc_container.hpp>
//#include <ext/pb_ds/tree_policy.hpp>
//#include <ext/pb_ds/priority_queue.hpp>
//using namespace __gnu_pbds;
using namespace std;
#define ll long long
#define ld long double
#define ull unsigned long long
#define mst(a, b) memset((a), (b), sizeof(a))
#define mp(a, b) make_pair(a, b)
#define pi acos(-1)
#define endl '\n'
#define pii pair<int, int>
#define pll pair<ll, ll>
#define pdd pair<double, double>
#define vi vector<int>
#define vl vector<ll>
#define pb push_back
#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
#define lowbit(x) x &(-x)
#define all(x) (x).begin(), (x).end()
#define sf(x) scanf("%d", &x)
#define pf(x) printf("%d\n", x)
#define debug(x) cout << x << endl
#define mod(x) (x % mod + mod) % mod
template <typename T>
void read(T &x)
{
x = 0;
char ch = getchar();
ll f = 1;
while (!isdigit(ch))
{
if (ch == '-')
f *= -1;
ch = getchar();
}
while (isdigit(ch))
{
x = x * 10 + ch - 48;
ch = getchar();
}
x *= f;
}
const int INF = 0x3f3f3f3f;
const ll inf = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-8;
const int maxn = 1e6 + 7;
const int maxm = 5e5 + 7;
const int mod = 1e9 + 7;
#define IO ios_base::sync_with_stdio(0), cin.tie(0), cout.tie(0);
//template<typename T> using ordered_set = tree<T,null_type,less<T>,rb_tree_tag,tree_order_statistics_node_update>;
ll f[maxn];
void init()
{
for (int i = 1; i <= 100000; ++i)
{ //枚举a1的大小 am=a1+2
for (int j = 3; i * j <= 100000; ++j)
{ //a1...am 枚举m的大小
f[i * j + 3]++;
f[(i + 1) * j + 1]--;
f[(i + 1) * j + 2]--;
f[(i + 2) * j - 3 + 3]++;
}
}
for (int i = 2; i <= 100000; i++)
f[i] += f[i - 2]; //隔项差分
for (int i = 1; i <= 100000; i++)
f[i] += f[i - 1]; //差分
for (int i = 1; i <= 100000; i++)
f[i] += f[i - 1]; //前缀和
}
int main()
{
init();
int t;
sf(t);
for (int ii = 1; ii <= t; ++ii)
{
int l, r;
sf(l);
sf(r);
printf("Case #%d: %lld\n", ii, f[r] - f[l - 1]);
}
return 0;
}
F
题意
解法
代码
//将内容替换成代码
G
题意
每张牌有四个属性,每个属性有三种选择,同时有一种万能牌,它的属性可以是任意选择,一组牌共三张,要求找到一组牌的四个属性分别要么全部相同,要么两两完全不相同。
解法
暴力记录存在的每一种牌(属性有不同),遍历选择两张牌,看符合要求的另一张牌是否存在。
代码
#include <stdio.h>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <unordered_map>
#include <vector>
using namespace std;
typedef long long ll;
#define P pair<ll, ll>
const ll maxn = 2e5 + 111;
struct node {
int a, b, c, d;
} nn[300];
char s[100];
vector<int> vis[5][5][5][5];
int main() {
int T;
scanf("%d", &T);
for (int ii = 1; ii <= T; ++ii) {
for (int i = 0; i < 5; ++i) {
for (int j = 0; j < 5; ++j) {
for (int k = 0; k < 5; ++k) {
for (int l = 0; l < 5; ++l) {
vis[i][j][k][l].clear();
}
}
}
}
int n;
scanf("%d", &n);
for (int i = 1; i <= n; ++i) {
scanf("%s", s);
int cnt = 1;
for (int j = 0; s[j] != '\0'; ++j) {
if (s[j] == ']') {
continue;
}
if (s[j] == '[') {
continue;
}
if (cnt == 1) {
if (s[j] == 'o') {
nn[i].a = 1;
} else if (s[j] == 't' && s[j + 1] == 'w') {
nn[i].a = 2;
} else if (s[j] == 't' && s[j + 1] == 'h') {
nn[i].a = 3;
} else
nn[i].a = 4;
while (s[j] != ']') {
++j;
}
++cnt;
} else if (cnt == 2) {
if (s[j] == 'd') {
nn[i].c = 1;
} else if (s[j] == 's') {
nn[i].c = 2;
} else if (s[j] == 'o') {
nn[i].c = 3;
} else
nn[i].c = 4;
while (s[j] != ']') {
++j;
}
++cnt;
} else if (cnt == 3) {
if (s[j] == 's' && s[j + 1] == 't') {
nn[i].b = 1;
} else if (s[j] == 's' && s[j + 1] == 'o') {
nn[i].b = 2;
} else if (s[j] == 'o') {
nn[i].b = 3;
} else
nn[i].b = 4;
while (s[j] != ']') {
++j;
}
++cnt;
} else {
if (s[j] == 'r') {
nn[i].d = 1;
} else if (s[j] == 'g') {
nn[i].d = 2;
} else if (s[j] == 'p') {
nn[i].d = 3;
} else
nn[i].d = 4;
while (s[j] != ']') {
++j;
}
++cnt;
}
}
vis[nn[i].a][nn[i].b][nn[i].c][nn[i].d].push_back(i);
}
int ans[3];
int flag = 0;
for (int i = 1; i <= n; ++i) {
for (int j = i + 1; j <= n; ++j) {
vector<int> aa, bb, cc, dd;
if (nn[i].a == 4 || nn[j].a == 4) {
aa.push_back(1);
aa.push_back(2);
aa.push_back(3);
aa.push_back(4);
// a=1,2,3,4
} else if (nn[i].a == nn[j].a) {
// a=nn[i].a.4
aa.push_back(nn[i].a);
aa.push_back(4);
} else {
// a=6-nn[i].a-nn[j].a,4
aa.push_back(6 - nn[i].a - nn[j].a);
aa.push_back(4);
}
if (nn[i].b == 4 || nn[j].b == 4) {
bb.push_back(1);
bb.push_back(2);
bb.push_back(3);
bb.push_back(4);
// b=1,2,3,4
} else if (nn[i].b == nn[j].b) {
// b=nn[i].b.4
bb.push_back(nn[i].b);
bb.push_back(4);
} else {
// b=6-nn[i].b-nn[j].b,4
bb.push_back(6 - nn[i].b - nn[j].b);
bb.push_back(4);
}
if (nn[i].c == 4 || nn[j].c == 4) {
cc.push_back(1);
cc.push_back(2);
cc.push_back(3);
cc.push_back(4);
// c=1,2,3,4
} else if (nn[i].c == nn[j].c) {
// c=nn[i].c.4
cc.push_back(nn[i].c);
cc.push_back(4);
} else {
// c=6-nn[i].c-nn[j].c,4
cc.push_back(6 - nn[i].c - nn[j].c);
cc.push_back(4);
}
if (nn[i].d == 4 || nn[j].d == 4) {
dd.push_back(1);
dd.push_back(2);
dd.push_back(3);
dd.push_back(4);
// d=1,2,3,4
} else if (nn[i].d == nn[j].d) {
// d=nn[i].d.4
dd.push_back(nn[i].d);
dd.push_back(4);
} else {
// d=6-nn[i].d-nn[j].d,4
dd.push_back(6 - nn[i].d - nn[j].d);
dd.push_back(4);
}
for (auto a_ : aa) {
for (auto b_ : bb) {
for (auto c_ : cc) {
for (auto d_ : dd) {
for (auto w : vis[a_][b_][c_][d_]) {
if (w != i && w != j) {
ans[0] = i, ans[1] = j, ans[2] = w;
flag = 1;
goto zj;
}
}
}
}
}
}
}
}
zj:
if (!flag) {
printf("Case #%d: -1\n", ii);
} else
printf("Case #%d: %d %d %d\n", ii, ans[0], ans[1], ans[2]);
}
return 0;
}
H
题意
解法
代码
//将内容替换成代码
I
题意
∙
\bullet
∙ 给了两个数组 $\left { a_1,a_2,\dots,a_n \right } $ 和 $\left { b_1,b_2,\dots,b_n \right } $
∙
\bullet
∙ 有
n
n
n 次操作,每次操作选择一个数
a
i
a_i
ai 或
b
i
b_i
bi。
∙
\bullet
∙ 要求最后选择的不同的数最多。
解法
先离散化,然后每次对
a
i
a_i
ai 和
b
i
b_i
bi 连边,可以发现在一个连通图中,如果存在环,那么这几个数一定可以全部取到,否则有一个数取不到,因为可以把每次操作看作的选择一个边和连接边的一个点,那么如果不存在环就是一个树形结构,根节点在最后取不到。如果存在环就可以首尾相接所有点都可以取到。
使用并查集来维护一些联通的点,使用类似拓扑排序的方法找环即可。
代码
#include <stdio.h>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <unordered_map>
#include <vector>
using namespace std;
typedef long long ll;
#define P pair<int, int>
const int maxn = 2e5 + 111;
int a[maxn], b[maxn], c[maxn * 2];
int n, len;
int pre[maxn];
struct node {
vector<int> to;
int in; //入度
} nn[maxn];
vector<int> G[maxn];
int findroot(int x) { return pre[x] == x ? pre[x] : pre[x] = findroot(pre[x]); }
inline void link(int x, int y) { pre[findroot(x)] = findroot(y); }
int getid(int x) { return lower_bound(c + 1, c + 1 + len, x) - c; }
bool dfs(int u) {
queue<int> q;
vector<int> vec;
for (auto w : G[u]) {
if (nn[w].in == 1) {
q.push(w);
}
}
while (!q.empty()) {
int tp = q.front();
q.pop();
vec.push_back(tp);
for (auto v : nn[tp].to) {
--nn[v].in;
--nn[tp].in;
if (nn[v].in == 1) {
q.push(v);
}
}
}
return vec.size() - G[u].size();
}
int main() {
int T;
scanf("%d", &T);
for (int ii = 1; ii <= T; ++ii) {
scanf("%d", &n);
for (int i = 1; i <= n; ++i) {
scanf("%d%d", a + i, b + i);
c[2 * i] = a[i], c[2 * i - 1] = b[i];
}
sort(c + 1, c + 1 + 2 * n);
len = unique(c + 1, c + 1 + 2 * n) - c - 1;
for (int i = 1; i <= len; ++i) {
pre[i] = i;
nn[i].to.clear();
G[i].clear();
nn[i].in = 0;
}
for (int i = 1; i <= n; ++i) {
a[i] = getid(a[i]);
b[i] = getid(b[i]);
nn[a[i]].to.push_back(b[i]);
nn[b[i]].to.push_back(a[i]);
++nn[a[i]].in, ++nn[b[i]].in;
}
for (int i = 1; i <= n; ++i) {
link(a[i], b[i]);
}
int ans = len;
for (int i = 1; i <= len; ++i) {
G[findroot(i)].push_back(i);
}
for (int i = 1; i <= len; ++i) {
if (pre[i] == i) {
--ans;
ans += dfs(i);
}
}
printf("Case #%d: %d\n", ii, ans);
}
return 0;
}
/*
1
4
9 10
2 4
1 2
1 7
*/
J
题意
解法
代码
//将内容替换成代码
K
题意
餐馆一共 n n n种食物,每种食物利润为 a i a_{i} ai,数量为 b i b_{i} bi,每个顾客必须从第一道菜吃起,问最多能招待多少名顾客,在人最多情况下利润最高为多少。
解法
最多招待的顾客数必然是第一个菜品的数量,维护利润的前缀和,然后维护两个数组分别记录当前菜品之前利润最高的菜品的利润和菜品编号和当前菜品之前数量最少的菜品的数量和菜品编号。从利润最高的菜品开始,寻找它之前数量最少的菜品数量作为吃到这道菜的顾客数量,然后在找到数量最少的菜品以前找利润最高的菜品,不断找下去直到第一道菜,最后计算最大利润。
代码
#pragma region
#include <algorithm>
#include <cmath>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <unordered_map>
#include <vector>
using namespace std;
typedef long long ll;
#define rep(i, a, n) for (int i = a; i <= n; ++i)
#define per(i, a, n) for (int i = n; i >= a; --i)
namespace fastIO {
#define BUF_SIZE 100000
#define OUT_SIZE 100000
//fread->R
bool IOerror = 0;
//inline char nc(){char ch=getchar();if(ch==-1)IOerror=1;return ch;}
inline char nc() {
static char buf[BUF_SIZE], *p1 = buf + BUF_SIZE, *pend = buf + BUF_SIZE;
if (p1 == pend) {
p1 = buf;
pend = buf + fread(buf, 1, BUF_SIZE, stdin);
if (pend == p1) {
IOerror = 1;
return -1;
}
}
return *p1++;
}
inline bool blank(char ch) { return ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t'; }
template <class T>
inline bool R(T &x) {
bool sign = 0;
char ch = nc();
x = 0;
for (; blank(ch); ch = nc())
;
if (IOerror) return false;
if (ch == '-') sign = 1, ch = nc();
for (; ch >= '0' && ch <= '9'; ch = nc()) x = x * 10 + ch - '0';
if (sign) x = -x;
return true;
}
inline bool R(double &x) {
bool sign = 0;
char ch = nc();
x = 0;
for (; blank(ch); ch = nc())
;
if (IOerror) return false;
if (ch == '-') sign = 1, ch = nc();
for (; ch >= '0' && ch <= '9'; ch = nc()) x = x * 10 + ch - '0';
if (ch == '.') {
double tmp = 1;
ch = nc();
for (; ch >= '0' && ch <= '9'; ch = nc())
tmp /= 10.0, x += tmp * (ch - '0');
}
if (sign)
x = -x;
return true;
}
inline bool R(char *s) {
char ch = nc();
for (; blank(ch); ch = nc())
;
if (IOerror)
return false;
for (; !blank(ch) && !IOerror; ch = nc())
*s++ = ch;
*s = 0;
return true;
}
inline bool R(char &c) {
c = nc();
if (IOerror) {
c = -1;
return false;
}
return true;
}
template <class T, class... U>
bool R(T &h, U &... t) { return R(h) && R(t...); }
#undef OUT_SIZE
#undef BUF_SIZE
}; // namespace fastIO
using namespace fastIO;
template <class T>
void _W(const T &x) { cout << x; }
void _W(const int &x) { printf("%d", x); }
void _W(const int64_t &x) { printf("%lld", x); }
void _W(const double &x) { printf("%.16f", x); }
void _W(const char &x) { putchar(x); }
void _W(const char *x) { printf("%s", x); }
template <class T, class U>
void _W(const pair<T, U> &x) { _W(x.F), putchar(' '), _W(x.S); }
template <class T>
void _W(const vector<T> &x) {
for (auto i = x.begin(); i != x.end(); _W(*i++))
if (i != x.cbegin()) putchar(' ');
}
void W() {}
template <class T, class... U>
void W(const T &head, const U &... tail) { _W(head), putchar(sizeof...(tail) ? ' ' : '\n'), W(tail...); }
#pragma endregion
const int maxn = 1e5 + 5;
__int128 a[maxn], b[maxn];
pair<__int128, __int128> aa[maxn], bb[maxn];
inline __int128 read() {
__int128 x = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9') {
if (ch == '-')
f = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = x * 10 + ch - '0';
ch = getchar();
}
return x * f;
}
inline void print(__int128 x) {
if (x < 0) {
putchar('-');
x = -x;
}
if (x > 9)
print(x / 10);
putchar(x % 10 + '0');
}
int main() {
int T;
scanf("%d", &T);
rep(cas, 1, T) {
int n;
scanf("%d", &n);
rep(i, 1, n) {
a[i] = read();
a[i] += a[i - 1];
}
rep(i, 1, n) b[i] = read();
int pos1 = 1, pos2 = 1;
rep(i, 1, n) {
if (a[i] > a[pos1]) pos1 = i;
if (b[i] < b[pos2]) pos2 = i;
aa[i] = {a[pos1], pos1};
bb[i] = {b[pos2], pos2};
}
__int128 num = 0, now = aa[n].second;
__int128 ans = 0;
while (bb[now].first > num) {
ans += (bb[now].first - num) * aa[now].first;
num = bb[now].first;
if (now == 1) break;
now = aa[bb[now].second - 1].second;
}
printf("Case #%d: ", cas);
print(b[1]);
printf(" ");
print(ans);
printf("\n");
}
}