专栏文章
题解:CF850D Tournament Construction
CF850D题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @min4zjxw
- 此快照首次捕获于
- 2025/12/01 20:39 3 个月前
- 此快照最后确认于
- 2025/12/01 20:39 3 个月前
考察兰道定理的证明。
首先由题目知兰道定理是充要条件,则直接 出符合定理要求的得分序列即可。观察 和 的增长速度可知最大的 在 左右,该部分复杂度为 ,其中 。
然后构造一个竞赛图。先令 存在当且仅当 ,此时我们将得到得分序列 。设最终得分序列需要为 (已排序),则使用如下调整法构造:
- 找到最小的 ,使得 。若有多个,找 最大的那一个;
- 找到 后面的最小 ,使得 。
- 此时 和 差值至少是 ,则一定有点 满足路径 存在(否则差值最大是 ),反转这条路径,有 ;
- 结合兰道定理的必要性知最开始 的前缀和数组达到下界,且整个过程中 的前缀和数组的每个位置不大于 的对应位置,因此总能找到 。这便是兰道定理充分性的证明。
/* K_crane x N_cat */
#include <bits/stdc++.h>
#define lowbit(x) ((x) & (-(x)))
using namespace std;
const int N = 65;
int m, a[N], n, s[N], t[N]; bool dp[35][N][N * 35], mp[N][N];
inline bool check(int n, int sum) {return (sum >= n * (n - 1) / 2);}
inline void flip(int x, int y) {mp[x][y] ^= 1, mp[y][x] ^= 1;}
inline void take(int ID, int remain, int val)
{
if(!ID && !remain && !val) return ;
if(val >= a[ID] && dp[ID][remain - 1][val - a[ID]])
take(ID, remain - 1, val - a[ID]), s[++n] = a[ID];
else if(val >= a[ID] && dp[ID - 1][remain - 1][val - a[ID]])
take(ID - 1, remain - 1, val - a[ID]), s[++n] = a[ID];
else assert(0);
}
inline bool judge()
{
for(int i = 1; i <= n; ++i) if(s[i] != t[i]) return true;
return false;
}
int main()
{
// freopen("text.in", "r", stdin);
// freopen("prog.out", "w", stdout);
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
cin >> m;
for(int i = 1; i <= m; ++i) cin >> a[i];
sort(a + 1, a + m + 1);
dp[0][0][0] = true;
for(int i = 0; i <= m; ++i)
{
for(int j = 0; j <= 61; ++j)
{
for(int k = 0; k <= j * 30; ++k)
{
if(i && check(j + 1, k + a[i])) dp[i][j + 1][k + a[i]] |= dp[i][j][k];
if(check(j + 1, k + a[i + 1])) dp[i + 1][j + 1][k + a[i + 1]] |= dp[i][j][k];
}
}
}
for(int i = 1; i <= 62; ++i)
{
bool flag = false;
for(int j = 0; j <= i * 30; ++j)
if(dp[m][i][j] && i * (i - 1) / 2 == j)
{flag = true; take(m, i, j); break;}
if(flag) break;
if(i == 62) {cout << "=(" << '\n'; return 0;}
}
for(int i = 1; i <= n; ++i)
for(int j = 1; j < i; ++j)
mp[i][j] = true, ++t[i];
while(judge())
{
int p = 0, q = 0;
for(int i = 1; i <= n; ++i) if(t[i] < s[i]) {p = i; break;}
while(t[p] == t[p + 1]) ++p;
for(int i = p + 1; i <= n; ++i) if(t[i] > s[i]) {q = i; break;}
if(mp[q][p]) flip(p, q), --t[q], ++t[p];
else
{
for(int i = 1; i <= n; ++i)
{
if(mp[q][i] && mp[i][p])
{flip(q, i), flip(i, p); --t[q], ++t[p]; break;}
}
}
}
cout << n << '\n';
for(int i = 1; i <= n; ++i)
{
for(int j = 1; j <= n; ++j)
cout << mp[i][j];
cout << '\n';
}
return 0;
}
/*
*/
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...