长安大学第四届ACM-ICPC“迎新杯”程序设计竞赛-重现赛 G - 彩虹岛套娃
题目描述
俄罗斯套娃是俄罗斯特产的木制玩具,一般由多个一样图案的空心木娃娃一个套一个组成,最多可达十多个,通常为圆柱形,底部平坦可以直立。颜色有红色,蓝色,绿色,紫色等。最普通的图案是一个穿着俄罗斯民族服装的姑娘,叫做“玛特罗什卡”,这也成为这种娃娃的通称。
彩虹岛也有自己的套娃,不过与俄罗斯套娃有所不同,其组成规则如下:1. 空心木娃娃只有正方体与球两种形状。
2. 正方体娃娃与球体娃娃可以相互套,也可以相同形状之间套。
3. 当两形状相切的时候使能够互相嵌套的,比如半径为2的球体能套在边长为4的正方体中。
4. 所有木娃娃的厚度可以忽略不计。
现在有𝑛个正方体和𝑚个球形的木娃娃,其中第𝑖个正方体娃娃边长为𝑎𝑖,第𝑗个球形娃娃半径为𝑟𝑗。用这些娃娃组成一个套娃,最多有几层?
数据保证所有正方体边长不相同,所有的圆半径不相同。
输入描述:
输入第一行为一个整数𝑇(1 ≤ 𝑇 ≤ 25),表示一共有𝑇组测试数据。
对于每组测试数据:
第一行有两个整数𝑛,𝑚(1 ≤ 𝑛,𝑚 ≤ 105),分别表示正方体和球体的木娃娃数。
第二行有𝑛个整数,其中第𝑖个整数𝑎𝑖(1 ≤ 𝑎𝑖 ≤ 109)代表第𝑖个正方体娃娃的边长。
第二行有𝑚个整数,其中第𝑖个整数𝑟𝑖(1 ≤ 𝑟𝑖 ≤ 109)代表第𝑖个球形娃娃的半径。
输出描述:
输出一个正整数𝑥,表示组成的套娃的层数。
示例1
输入
1 3 4 2 4 6 7 5 3 1
输出
5
说明
对于样例,套娃分别由半径为7的球形、半径为5的球形、边长为4的正方体、边长为2的正方体、半径为1 的球形的木娃娃组成,一共5层。
题解
$dp$。
可以构造出一个$DAG$,然后看最长路的长度就可以了。
#include <bits/stdc++.h> using namespace std; const int maxn = 8e5 + 10; int T; int n, m; long long a[maxn], b[maxn]; int dp[maxn]; int h[maxn]; int to[maxn]; int nx[maxn]; int sz; int in[maxn]; void add(int x, int y) { // cout << x << " -> " << y <<endl; to[sz] = y; nx[sz] = h[x]; h[x] = sz; sz ++; } int main() { scanf("%d", &T); while(T --) { scanf("%d%d", &n, &m); int ans = 0; sz = 0; for(int i = 1; i <= n + m; i ++) { h[i] = -1; in[i] = 0; dp[i] = 0; } for(int i = 1; i <= n; i ++) { scanf("%lld", &a[i]); if(i < n) { add(i, i + 1); in[i + 1] ++; } } for(int i = 1; i <= m; i ++) { scanf("%lld", &b[i]); if(i < m) { add(i + n, i + 1 + n); in[i + 1 + n] ++; } } sort(a + 1, a + 1 + n); sort(b + 1, b + 1 + m); for(int i = 1; i <= n; i ++) { int L = 1, R = m, pos = -1; while(L <= R) { int mid = (L + R) / 2; if(2LL * b[mid] <= a[i]) { L = mid + 1; pos = mid; } else { R = mid - 1; } } if(pos != -1) { add(pos + n, i); in[i] ++; } } for(int i = 1; i <= m; i ++) { int L = 1, R = n, pos = -1; while(L <= R) { int mid = (L + R) / 2; if(3LL * a[mid] * a[mid] <= 4LL * b[i] * b[i]) { L = mid + 1; pos = mid; } else { R = mid - 1; } } if(pos != -1) { add(pos, i + n); in[i + n] ++; } } queue<int> Q; for(int i = 1; i <= n + m; i ++) { if(in[i] == 0) { Q.push(i); dp[i] = 1; } } while(!Q.empty()) { int node = Q.front(); Q.pop(); ans = max(ans, dp[node]); for(int i = h[node]; i != -1; i = nx[i]) { dp[to[i]] = max(dp[to[i]], dp[node] + 1); in[to[i]] --; if(in[to[i]] == 0) { Q.push(to[i]); } } } printf("%d\n", ans); } return 0; }