Loading

CF850D 做题感想

题目链接

关注 zyf ,顿顿解馋。

这道题目一看就一脸不可做的样子。。。
当然,如果你不知道竞赛图的性质,确实是非常不可做的。

竞赛图:任意两个点之间都有一条有向边连接,也就是把完全图的每一条边都赋予一个方向。
现在来看一下给你一个有关 \(n\) 个点的出度 \(deg_i\) 判断是否构成竞赛图。
兰道定理:对 \(deg_i\) 升序排好后, 若满足 \(\sum\limits_{i=1}^kdeg_i\geq C_k^2\)\(\sum deg_i=C_n^2\) , 定能构造出一种竞赛图 。

现在考虑先构造出来一个序列 \(deg_i\) ,再由 \(deg_i\) 直接构造初始的竞赛图。
假设一共有 \(n\) 个点,容易发现 \(n\leq 61\)
因为有题目可以发现 \(m\leq 31\) ,然后可以列出方程:

\[\begin{split} \frac{n\times(n+1)}{2}&\leq 31n\\ n&\leq31 \end{split} \]

接着我们用 \(F(i,j,k)\) 表示当前排到了第 \(i\) 个点,当前点度数为 \(a_j\) ,度数总和为 \(k\) 是否可行。
边界情况是 \(F(1,1,a_1)=1\) 证明显然。
转移也是非常简单 \(F(i,j,k)=\min\{1,F(i-1,j,k-a_j)+F(i-1,j-1-a_{j-1})\}\)
本人为了方便 \(\tt dp\) 采用的是顺推法求解 \(F(i,j,k)\)
然后枚举每一个 \(i\in[1,61]\) 找到 \(F(i,m,\frac{i\times(i-1)}{2})=1\) 的最小的 \(i\)
自此我们就找到了能够成竞赛图的 \(n\) 的最小值。

至于还原原来的序列,直接记录一下是由哪一个状态递推过来的,倒推就可以还原原序列。
现在的问题是:给定一个出度的序列 \(deg_i\) 怎么去构造一个竞赛图。

这个还是非常简单的了,每一次连边按照出度 \(deg_i\) 升序排序,然后直接向后连边即可。
像是这样:

bool cmp (int a, int b) {return deg[a] < deg[b];}
for (int i = 1; i <= n; i++) {
  std::sort(pos + i, pos + 1 + n, cmp);
  for (int j = i + 1; j <= i + deg[pos[i]]; j++) ok[pos[i]][pos[j]] = 1;
  for (int j = i + deg[pos[i]] + 1; j <= n; j++) ok[pos[j]][pos[i]] = 1, deg[pos[j]] --;
}

所以细节的话可以直接看代码。

#include <set>
#include <map>
#include <cmath>
#include <queue>
#include <string>
#include <cstdio>
#include <cctype>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <unordered_map>

#define File(a) freopen(a".in", "r", stdin), freopen(a".out", "w", stdout)
#define quad putchar(' ')
#define Enter putchar('\n')

using std::abs;
using std::pair;
using std::string;
using std::make_pair;

// #define int long long

template <class T> void read(T &a);
template <class T> void write(T x);

template <class T, class ...rest> void read(T &a, rest &...x);
template <class T, class ...rest> void write(T x, rest ...a);

const int N = 105;

int m, a[N], limit[N], n, top, deg[N], tot, ok[N][N], pos[N];
int f[65][35][1905], sta[N], g[65][35][1905];

inline void Get_degree() {
  int ii, jj, kk;
  ii = n; jj = m; kk = n * (n - 1) / 2;
  while (1) {
    sta[++top] = a[jj];
    if (g[ii][jj][kk] == 1) {
      ii --; kk -= a[jj]; jj --;
    } else if (g[ii][jj][kk] == 2){
      ii --; kk -= a[jj];
    } else break;
  }
  while (top) deg[++tot] = sta[top], top --;
  return ;
}

bool cmp(int a, int b) {return deg[a] < deg[b]; }

signed main(void) {
  read(m);
  for (int i = 1; i <= m; i++) read(a[i]);
  std::sort(a + 1, a + 1 + m);
  for (int i = 1; i <= 80; i++) limit[i] = i * (i - 1) / 2;
  f[1][1][a[1]] = 1;
  for (int i = 1; i <= 61; i++) // 当前的点数
    for (int j = 1; j <= m; j++) // 当前度数可以使用 a[1]~a[j]
      for (int k = limit[i]; k <= i * a[j]; k++) // 当前的度数的总和
        if (f[i][j][k] == 1) {
          f[i + 1][j + 1][k + a[j + 1]] = f[i + 1][j][k + a[j]] = 1;
          g[i + 1][j + 1][k + a[j + 1]] = 1;
          g[i + 1][j][k + a[j]] = 2;
        }
  for (int i = 1; i <= 61; i++)
    if (f[i][m][i * (i - 1) / 2] == 1) {n = i; break;}
  if (n == 0) {std::cout << "=(" << std::endl; return 0;}
  Get_degree();
  // for (int i = 1; i <= n; i++) write(deg[i]), quad; Enter;
  write(n); Enter;
  for (int i = 1; i <= n; i++) pos[i] = i;
  for (int i = 1; i <= n; i++) {
    std::sort(pos + i, pos + 1 + n, cmp);
    // for (int j = 1; j <= n; j++) write(deg[pos[j]]), quad; Enter;
    for (int j = i + 1; j <= i + deg[pos[i]]; j++) ok[pos[i]][pos[j]] = 1;
    for (int j = i + deg[pos[i]] + 1; j <= n; j++) ok[pos[j]][pos[i]] = 1, deg[pos[j]] --;
  }
  for (int i = 1; i <= n; i++, Enter)
    for (int j = 1; j <= n; j++) write(ok[i][j]);
  return 0;
}

template <class T> void read(T &a) {
  int s = 0, t = 1;
  char c = getchar();
  while (!isdigit(c) && c != '-') c = getchar();
  if (c == '-') c = getchar(), t = -1;
  while (isdigit(c)) s = s * 10 + c - '0', c = getchar();
  a = s * t;
}
template <class T> void write(T x) {
  if (x == 0) putchar('0');
  if (x < 0) putchar('-'), x = -x;
  int top = 0, sta[50] = {0};
  while (x) sta[++top] = x % 10, x /= 10;
  while (top) putchar(sta[top] + '0'), top --;
  return ;
}

template <class T, class ...rest> void read(T &a, rest &...x) {
  read(a); read(x...);
}
template <class T, class ...rest> void write(T x, rest ...a) {
  write(x); quad; write(a...);
}
posted @ 2022-07-18 19:59  Aonynation  阅读(27)  评论(0编辑  收藏  举报