2022NOIP A层联测16
A. 平衡(balance)
打表找规律,发现一定是 \(+1 -1\) 交替, 因为是环,转回来的话必须是奇数,所以偶数无解
code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
int read(){
int x = 0; char c = getchar();
while(!isdigit(c))c = getchar();
do{x = x * 10 + (c ^ 48); c = getchar();}while(isdigit(c));
return x;
}
const int maxn = 1000005;
int n, a[maxn];
void sol(){
n = read();
if((n & 1) == 0){
printf("NO\n");
return;
}
printf("YES\n");
a[1] = 1;
int p = 1;
for(int i = 1; i * 4 <= n + n; ++i){
a[++p] = i * 4;
if(i * 4 + 1 <= n + n)a[++p] = i * 4 + 1;
}
for(int i = 2; i <= n + n; ++i)if(i % 4 != 0 && i % 4 != 1)a[++p] = i;
for(int i = 1; i <= n + n; ++i)printf("%d ", a[i]);
}
int main(){
freopen("balance.in","r",stdin);
freopen("balance.out","w",stdout);
int t = read();
for(int i = 1; i <= t; ++i)sol();
return 0;
}
B. 二择(choice)
一组 \(n\) 个匹配需要 \(2n\) 个点,那么随便找一个极大匹配,合法输出,不合法一定满足有至少 \(n\) 个没有边的点
code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
int read(){
int x = 0; bool f = 0; char c = getchar();
while(!isdigit(c)){f = c == '-'; c = getchar();}
do{x = x * 10 + (c ^ 48); c = getchar();}while(isdigit(c));
return f ? -x : x;
}
const int maxn = 1500005;
int n, m;
struct edge{int u, v;}e[maxn];
bool vis[maxn];
vector<int> ans;
void sol(){
n = read(), m = read();
for(int i = 1; i <= m; ++i){
int u = read(), v = read();
e[i] = {u, v};
}
ans.clear();
for(int i = 1; i <= n + n + n; ++i)vis[i] = false;
for(int i = 1; i <= m; ++i){
int u = e[i].u, v = e[i].v;
if(vis[u] || vis[v])continue;
vis[u] = vis[v] = 1;
ans.push_back(i);
}
if(ans.size() >= n){
printf("Beta2\n");
for(int i = 0; i < n; ++i)printf("%d ",ans[i]);printf("\n");
return;
}
ans.clear();
for(int i = 1; i <= n + n + n; ++i)if(!vis[i])ans.push_back(i);
printf("Beta1\n");
for(int i = 0; i < n; ++i)printf("%d ",ans[i]);printf("\n");
}
int main(){
freopen("choice.in","r",stdin);
freopen("choice.out","w",stdout);
int t = read();
for(int i = 1; i <= t; ++i)sol();
return 0;
}
C. 数塔(pyramid)
二分答案,转化为 \(1 / 0\)
然后观察性质,写成正三角(居中对齐)
如果存在连续的一段(至少两个) \(1 / 0\) 那么他们上面一定都是他们,而且如果与之相邻的有 \(1 / 0\) 交错,那么他会每次扩展一个
所以当存在连续段时,找到最先扩展到正中间的即为答案
如果全是 \(1 / 0\) 交错,那么直接取两边即可
code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
int read(){
int x = 0; char c = getchar();
while(!isdigit(c))c = getchar();
do{x = x * 10 + (c ^ 48); c = getchar();}while(isdigit(c));
return x;
}
const int maxn = 300005;
int n;
int a[maxn], b[maxn];
bool check(int mid){
for(int i = 1; i <= n + n - 1; ++i)b[i] = a[i] >= mid;
for(int i = n - 1, j = n + 1; i >= 1 && j <= n + n - 1; --i, ++j){
if(b[i] == b[i + 1])return b[i];
if(b[j] == b[j - 1])return b[j];
}
return b[1];
}
void sol(){
n = read();
for(int i = 1; i <= n + n - 1; ++i)a[i] = read();
int l = 1, r = n + n - 1, ans;
while(l <= r){
int mid = (l + r) >> 1;
if(check(mid))l = mid + 1, ans = mid;
else r = mid - 1;
}
printf("%d\n",ans);
}
int main(){
freopen("pyramid.in","r",stdin);
freopen("pyramid.out","w",stdout);
int t = read();
for(int i = 1; i <= t; ++i)sol();
return 0;
}
D. 环游(tour)
发现能走直接走,不能走才会跳跃,而且最多跳 \(log\) 次
于是对 \(log\) 种长度,把直接能到的位置看成一个点
考场想到这里就去考虑树形 \(DP\) 了
考虑状压,每个深度我们只能选择一次,那么状态就压选过的深度
考虑每次我们会从一个子段出发,于是我们还需要走一个前缀和一个后缀,于是分 \(pre, suf\) 进行转移
令 \(pre[s]\) 表示使用了 \(s\) 深度, 能够拼出的最长前缀
\(suf\) 类似,转移考虑新拼上一段未出现的深度
统计答案的时候,枚举前缀使用的状态 \(s_1\), 后缀使用其补集,看能否完全覆盖整个区间
因为我们最多跳 \(log\) 次,所以区间多于 \(log\) 无解,于是总的复杂度为 \(vlog^2v\)
code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
int read(){
int x = 0; bool f = 0; char c = getchar();
while(!isdigit(c)){f = c == '-'; c = getchar();}
do{x = x * 10 + (c ^ 48); c = getchar();}while(isdigit(c));
return f ? -x : x;
}
const int maxn = 300005;
int n, v, x[maxn];
int l[19][maxn], r[19][maxn];
int pre[1 << 19], suf[1 << 19];
int main(){
freopen("tour.in","r",stdin);
freopen("tour.out","w",stdout);
n = read(), v = read();
for(int i = 1; i <= n; ++i)x[i] = read();
int mx = __lg(v) + 1;
for(int i = 0; i <= mx; ++i){
l[i][1] = 1; r[i][n] = n;
for(int j = 1 + 1; j <= n; ++j)if(x[j] - x[j - 1] <= (v >> i))l[i][j] = l[i][j - 1]; else l[i][j] = j;
for(int j = n - 1; j >= 1; --j)if(x[j + 1] - x[j] <= (v >> i))r[i][j] = r[i][j + 1]; else r[i][j] = j;
}
memset(suf, 0x3f, sizeof(suf));
suf[0] = n + 1;
for(int i = 0; i < (1 << mx); ++i){
for(int j = 1; j <= mx; ++j){
if((i >> (j - 1)) & 1)continue;
pre[i | (1 << (j - 1))] = max(pre[i | (1 << (j - 1))], r[j][min(pre[i] + 1, n)]);
suf[i | (1 << (j - 1))] = min(suf[i | (1 << (j - 1))], l[j][max(suf[i] - 1, 1)]);
}
}
int cnt = 0;
for(int i = 1; i <= n; i = r[0][i] + 1) ++cnt;
if(cnt > mx + 1){
for(int i = 1; i <= n; ++i)printf("Impossible\n");
}else{
for(int i = 1; i <= n; i = r[0][i] + 1){
bool fl = false;
for(int j = 0; j < (1 << mx) && !fl; ++j)if(pre[j] >= i - 1 && suf[((1 << mx) - 1) ^ j] <= r[0][i] + 1)fl = 1;
for(int j = i; j <= r[0][i]; ++j)if(fl)printf("Possible\n");else printf("Impossible\n");
}
}
return 0;
}

浙公网安备 33010602011771号