长安大学第四届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;
}

  

posted @ 2017-12-21 15:23  Fighting_Heart  阅读(364)  评论(0编辑  收藏  举报