目录
广告:starrycoding \(9\) 折优惠码:
FV7B04LL
\(E\) 有空再补
构造场, 构造低手掉分.
A
不记得为什么卡了, 居然写了 \(7 \min\).
思路
\(n \le 10^2\), 甚至可以使用 \(n^3\) 算法.
枚举每个 \(a_i\), 判断 \(a_i\) 与 \(\{a_1,a_2,\ldots,a{i-1}\} \cup \{a_{i+1},a_{i+2},\ldots,a_n\}\) 组合后, 是否可以都不被 \(k\) 整除.
复杂度 \(O(n^2)\).
代码
void func(void)
{
int n,k;
cin >> n >> k;
vector<int> a(n+1);
for(int i=1;i<=n;++i) cin >> a[i];
for(int i=1;i<=n;++i)
{
int cnt = 0;
for(int j=1;j<=n;++j)
{
if(i == j) continue;
int X = abs(a[i]-a[j]);
if(X % k != 0) cnt ++;
}
if(cnt == n-1)
{
cout << "YES\n" << i << '\n';
return ;
}
}
cout << "NO\n";
}
B
思路
对于操作 \(2\), 每次操作, 若是区间内有 超过一半(向上取整), 的位置有 \(1\), 那么区间内所有数都为 \(1\).
起始必须放置一个 \(1\).
那么我们从 \(1\) 开始放置(俺寻思, 事实上放在中间, 左右轮流放不会影响结果, 不做证明了),
\(1\) 放置后, \(2\) 最多放置在 \(4((1+1) \cdot 2)\) 的位置, 才能满足 \(l \sim r\) 半数有 \(1\),
\(3\) 最多放置在 \(10((4+1) \cdot 2)\).
设当前 \(i\) 的总数为 \(cnt\).
可以得到, 第 \(i\) 个 \(1\), 可以放置在\((cnt+1) \cdot 2\) 的位置.
那么根据上述模拟即可.
复杂度 \(O(\log n)\)
代码
void func(void)
{
int n;
cin >> n;
int X = 1,cnt = 0;
while(X < n)
{
X = (X+1)*2;
cnt ++;
}
cout << cnt+1 << '\n';
}
C
赛时没战意, 这题都没出.
这题不是很好讲, 需要结合图推.
思路
不递减排列是满足条件的.
\(1,2,3,\ldots,n-1,n\), 满足条件.
要满足上述内容, 除了 \(n\) 之外的所有数, 两侧至少有一个 大于自己的数.
那么如果我们从 \(n\)开始放置:
\(n-1\) 可以放置在 \(n\) 在左右侧.
\(n-2\) 可以放在 整体 的左右, 但是不能方阵 \(n, n-1\) 之间, 因为会让 \(n-1\) 捕鱼 \(n\) 相邻, 就没有再比它大的数了.
那么从 \(n\) 放置到 \(1\), 每次只能放置在整体的左右.
但是若是从 \(n\) 开始放置, 不好判断字典序顺序(看下述可得).
反向考虑, 从 \(1\) 开始.
下述内容画一画就很明显了
\(1\) 只能防止在最左侧/最右侧.
\(2\) 只能防止在 \(1\) 只内的最左/最右(\(1\) 在左时, \(2\) 放在 \(1\) 由或 最右, 反之亦然. )
\(3\) 只能放在新区间的最左/最右.
那么总共有 \(2^{n-1}\) 种放法.
如果 \(1\) 在最前, 字典序就是前 \(2^{n-1}/2\)(也就是\(2^n-2\)).
否则, 字典序就是 \(2^{n-1}/2+1 \sim 2^{n-1}\).
对于 \(2\), 如果 \(2\) 在新区间最前, 其字典序在此范围的 \(1\sim 2^{n-3}\)
即如果 \(1\) 在最前, \(2\) 在最前的字典序范围 \(1 \sim 2^{n-3}\).
如果 \(1\) 在最后, \(2\) 在最后的字典序范围 \(2^{n-2}+1 \sim 2^{n-1}\).
又因为 \(2^n \gg sizeof(long long)\), 所以只能选择别的方法表示.
根据上述分析, 一次可以排除掉整体区间的 一半, 那么多次就是典型的 \(\log\).
那么可以把 \(2^n\) 和 \(k\) 表示为 \(n\) 和 \(\log{k}\)
具体看代码吧.
复杂度
代码
int qpow(int a,int b)// 快速幂
{
int res=1;
while(b)
{
if(b&1)res=res*a;
a=a*a;
b=b>>1;
}
return res;
}
void func(void)
{
int n,k;
cin >> n >> k;
vector<int> a(n+1);
int l = 1,r = n;
if(log2(k) > n-1)// c++ 内置log_2函数
{
cout << -1 << '\n';
return ;
}
for(int i=1;i<=n-1;++i)
{
if(!k || log2(k) <= n-i-1)
{
a[l ++] = i;
}
else
{
a[r --] = i;
k -= qpow(2,n-i-1);// 能够减去的数小于 10^12
}
}
a[r --] = n;
for(int i=1;i<=n;++i) cout << a[i] << ' ';
cout << '\n';
}
D
沟槽的领接表, 太久没写, 整体clear tle了, 多浪费 \(1h\), 但是多了一种思路.
一题三解, 真有我的.
前置知识: dfs
, 领接表
.
思路二需要: 埃氏筛
.
思路三需要 set
, set.lower_bound()
.
三解太耗精力, 之后可能会补充吧.
解法 \(1\)
思路
比较俺寻思, 但是感觉更好理解.
- 树
- 要求相邻两数差不为质数, 偶数 除了\(2\), 都不为质数.
- 总共只能使用 \(2\cdot n\) 个点.
先假设一条 \(5\) 条的链, 我们只放奇数, 那么:
是可以满足情况的.
但是若是点很少:
是放不下的.
再考虑花形:
三个点的链也属于花形.
整个图可以可以视作若干个上述小单元的组合(链和花).
每个小单元则只能使用 \(cnt_{点总数}\cdot 2\)个数.
而\(2\)不能使用, 每个单元必然有一个数不能放置.
如果填入 \(1\), 那么该单元就可以放满了:
那么从根节点出发, 每次优先放 \(1\), 其次放差 \(2\) 以外同奇偶性的数.
本质还是解法\(1\), 只是实现不同.
代码
void dfs(int p,int lp)
{
if(a[p].size() <= 1) return ;
int cnt = a[p].size() - 1;
stack<int> X;
if(ans[p]&1)
{
if(st2.lower_bound(ans[p]+1) != st2.end() && *st2.lower_bound(ans[p]+1) == ans[p]+1)
{
X.push(ans[p]+1);
st2.erase(ans[p]+1);
}
vector<int> stp;
while(X.size() != cnt)
{
int temp = *st1.begin(); st1.erase(temp);
if(temp != ans[p] + 2 && temp != ans[p]-2) X.push(temp);
else stp.push_back(temp);
}
for(auto &i : stp) st1.insert(i);
}
else
{
if(st1.lower_bound(ans[p]+1) != st1.end() && *st1.lower_bound(ans[p]+1) == ans[p]+1)
{
X.push(ans[p]+1);
st1.erase(ans[p]+1);
}
vector<int> stp;
while(X.size() != cnt)
{
int temp = *st2.begin(); st2.erase(temp);
if(temp != ans[p] + 2 && temp != ans[p]-2) X.push(temp);
else stp.push_back(temp);
}
for(auto &i : stp) st2.insert(i);
}
for(auto &i : a[p])
{
if(i == lp) continue;
ans[i] = X.top();
X.pop();
}
for(auto &i : a[p])
{
if(i == lp) continue;
dfs(i,p);
}
}
void func(void)
{
int n;
cin >> n;
for(int i=2;i<=n<<1;++i)
{
(i&1) == 1 ? st1.insert(i) : st2.insert(i);
}
for(int i=1;i<=n;++i) a[i].clear();
int x,y;
for(int i=1;i<n;++i)
{
cin >> x >> y;
a[x].push_back(y);
a[y].push_back(x);
}
a[1].push_back(0);
ans[1] = 1;
dfs(1,0);
for(int i=1;i<=n;++i) cout << ans[i] << ' ';
cout << '\n';
}
解法 \(2\)
从此视频学习: Codeforces Round 992 (Div. 2) 题目讲解 ABCDE (CF2040)
两个解法一直在 \(tle\), 只能找了题解.
思路
和解法 \(1\) 类似, 每个小单元最多使用 \(2\cdot k\) 个数. 而用 \(1\) 补 \(2\), 同奇偶性的数刚好在范围内.
代码
int X;
vector<int> a[N],ans(N);
void dfs(int p,int lp)
{
ans[p] = X --;
int cnt = 0;
for(auto &i : a[p])
{
if(i == lp) continue;
if(ans[p]-X == 2) X -= 2;
else if(ans[p]-X != 1 && (ans[p]-X)&1) X --;
cnt ++;
dfs(i,p);
}
int len = a[p].size();
}
void func(void)
{
int n;
cin >> n;
for(int i=1;i<=n;++i) a[i].clear();
int x,y;
for(int i=1;i<n;++i)
{
cin >> x >> y;
a[x].push_back(y);
a[y].push_back(x);
}
X = n<<1;
dfs(1,0);
for(int i=1;i<=n;++i) cout << ans[i] << ' ';
cout << '\n';
}
解法 \(3\)
起始思路, 根本没想到是领接表问题.
思路
既然每条边差都为非素数, 那么dfs
到每个点, 给子节点赋值 \(+\) 非素数即可. 复杂度懒得证明了.
代码
#include<bits/stdc++.h>
#define Start cin.tie(0), cout.tie(0), ios::sync_with_stdio(false)
#define PII pair<int,int>
#define x first
#define y second
#define ull unsigned long long
#define ll long long
using namespace std;
const int M = 1000000007;
const int N = 2e5 + 10;
int len;
bitset<N<<1> vis;
vector<int> v(1,1),pri,a[N],ans(N);
void func(void);
void dfs(int p,int lp)
{
int X = 0;
for(auto &i : a[p])
{
if(i == lp) continue;
while(vis[ans[p]+v[X]]) X ++;
ans[i] = ans[p] + v[X];
vis[ans[i]] = true;
dfs(i,p);
}
}
signed main(void)
{
Start;
int n = N<<1;
for(int i=2;i<=n;++i)
{
if(!vis[i]) pri.push_back(i);
for(int j=0;pri[j]<=n/i;++j)
{
v.push_back(pri[j] * i);
vis[pri[j] * i] = true;
if(i % pri[j] == 0) break;
}
}
len = v.size();
sort(v.begin(),v.end());
int _ = 1;
cin >> _;
while(_--) func();
return 0;
}
void func(void)
{
int n;
cin >> n;
vis.reset();
for(int i=1;i<=n;++i) a[i].clear();
int x,y;
for(int i=1;i<n;++i)
{
cin >> x >> y;
a[x].push_back(y);
a[y].push_back(x);
}
ans[1] = 1;
dfs(1,0);
for(int i=1;i<=n;++i) cout << ans[i] << ' ';
cout << '\n';
}
标签:temp,992,int,void,Codeforces,dfs,ans,push,Div
From: https://www.cnblogs.com/zerocloud01/p/18598166