"蔚来杯"2022牛客暑期多校训练营6
A.Array
给定\(\geqslant 2\)的整数\(a_1,a_2,...,a_n\),满足\(\sum\limits_{i=1}^n \frac{1}{a_i}\leqslant \frac{1}{2}\),构造一个循环数列,使得其任意长度为\(a_i\)的子区间都至少包含一个\(i\)
考虑\(\sum\limits_{i=1}^n\frac{1}{a_i}\leqslant\frac{1}{2}\),则有\(\sum\limits_{i=1}^n\frac{1}{2^{\lfloor\log_2(a_i)\rfloor}}\leqslant 1\),故我们将所有的\(a_i\)放缩为\(2^{\lfloor\log_2(a_i)\rfloor}\),并对其排序
然后开始构造,假定循环节最开始长度为1,如果遇到\(2^k\),则将循环节变成\(2^k\),并找到一个空位置填数。一定是存在空位的,我们知道放缩后\(\sum\limits_{i=1}^n \frac{1}{a_i}\leqslant 1\),对于\(a_i=2^l\)而言,它可以在循环节\(2^k\)里占用\(\frac{2^k}{2^l}\)个位置,显然有\(\sum \frac{1}{a_i}\leqslant 1\rightarrow\sum\frac{2^k}{2^l}\leqslant 2^k\),因此是一定存在空位的
/*program from Wolfycz*/
#include<map>
#include<set>
#include<cmath>
#include<cstdio>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
#define lMax 1e18
#define MK make_pair
#define iMax 0x7f7f7f7f
#define sqr(x) ((x)*(x))
#define pii pair<int,int>
#define UNUSED(x) (void)(x)
#define lowbit(x) ((x)&(-x))
using namespace std;
typedef long long ll;
typedef unsigned int ui;
typedef unsigned long long ull;
template<typename T>inline T read(T x) {
int f = 1; char ch = getchar();
for (; ch < '0' || ch>'9'; ch = getchar()) if (ch == '-') f = -1;
for (; ch >= '0' && ch <= '9'; ch = getchar()) x = (x << 1) + (x << 3) + ch - '0';
return x * f;
}
inline void print(int x) {
if (x < 0) putchar('-'), x = -x;
if (x > 9) print(x / 10);
putchar(x % 10 + '0');
}
const int K = 19, N = 1e6, M = 1 << K;
vector<int>vec[K];
int Ans[N + 10];
void Dfs(int pos, int _i) {
if (_i == K) return;
int len = 1 << _i;
if (!vec[_i].empty()) {
int temp = vec[_i].back();
vec[_i].pop_back();
for (int i = pos; i <= M; i += len)
Ans[i] = temp;
}
else {
Dfs(pos, _i + 1);
Dfs(pos + len, _i + 1);
}
}
int main() {
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
int n = read(0);
for (int i = 1; i <= n; i++) {
int x = read(0), Now = 1;
while (1 << Now <= x) Now++;
vec[Now - 1].push_back(i);
}
Dfs(1, 1), Dfs(2, 1);
printf("%d\n", M);
for (int i = 1; i <= M; i++)
printf("%d%c", max(Ans[i], 1), i == M ? '\n' : ' ');
return 0;
}
B.Eezie and Pie
给定一棵有根树,每个节点可以为它的\(0\sim d[i]\)级祖先贡献1的价值,问最终每个点的价值?
很裸的一个板子题,找\(d[i]\)级祖先用倍增,然后再用树剖 + 线段树
当然这样是没有必要的,找\(d[i]\)级祖先可以在DFS的时候维护一个栈,栈顶往下\(d[i]\)个即为其\(d[i]\)级祖先,然后树上差分一下就好
(比赛时用的倍增 + 树剖 + DFS序差分)
/*program from Wolfycz*/
#include<map>
#include<set>
#include<cmath>
#include<cstdio>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
#define lMax 1e18
#define MK make_pair
#define iMax 0x7f7f7f7f
#define sqr(x) ((x)*(x))
#define pii pair<int,int>
#define UNUSED(x) (void)(x)
#define lowbit(x) ((x)&(-x))
using namespace std;
typedef long long ll;
typedef unsigned int ui;
typedef unsigned long long ull;
template<typename T>inline T read(T x) {
int f = 1; char ch = getchar();
for (; ch < '0' || ch>'9'; ch = getchar()) if (ch == '-') f = -1;
for (; ch >= '0' && ch <= '9'; ch = getchar()) x = (x << 1) + (x << 3) + ch - '0';
return x * f;
}
inline void print(int x) {
if (x < 0) putchar('-'), x = -x;
if (x > 9) print(x / 10);
putchar(x % 10 + '0');
}
const int N = 2e6, K = 22;
int Sum[N + 10];
struct S2 {
int pre[(N << 1) + 10], now[N + 10], child[(N << 1) + 10], tot;
int Deep[N + 10], sz[N + 10], Heavy[N + 10], F[N + 10], Dfn[N + 10], Top[N + 10], Time;
void link(int x, int y) { pre[++tot] = now[x], now[x] = tot, child[tot] = y; }
void connect(int x, int y) { link(x, y), link(y, x); }
void dfs1(int x, int fa) {
Deep[x] = Deep[F[x] = fa] + (sz[x] = 1);
for (int p = now[x]; p; p = pre[p]) {
int son = child[p];
if (son == fa) continue;
dfs1(son, x);
sz[x] += sz[son];
if (!Heavy[x] || sz[Heavy[x]] < sz[son])
Heavy[x] = son;
}
}
void dfs2(int x, int fa) {
if (!x) return;
Dfn[x] = ++Time;
Top[x] = Heavy[fa] == x ? Top[fa] : x;
dfs2(Heavy[x], x);
for (int p = now[x]; p; p = pre[p]) {
int son = child[p];
if (son == fa || son == Heavy[x]) continue;
dfs2(son, x);
}
}
void Modify(int x, int y, int n) {
while (Top[x] != Top[y]) {
if (Deep[Top[x]] < Deep[Top[y]]) swap(x, y);
Sum[Dfn[Top[x]]]++, Sum[Dfn[x] + 1]--;
//ST.Modify(1, 1, n, Dfn[Top[x]], Dfn[x]);
x = F[Top[x]];
}
if (Deep[x] > Deep[y]) swap(x, y);
Sum[Dfn[x]]++, Sum[Dfn[y] + 1]--;
//ST.Modify(1, 1, n, Dfn[x], Dfn[y]);
}
int lg[N + 10], Jump[N + 10][K];
void prepare(int n) {
for (int i = 1; i <= n; ++i)
lg[i] = lg[i - 1] + (1 << lg[i - 1] == i);
for (int i = 1; i <= n; i++)
Jump[i][0] = F[i];
for (int j = 1; j < K; j++)
for (int i = 1; i <= n; i++)
Jump[i][j] = Jump[Jump[i][j - 1]][j - 1];
}
int Query(int x, int d) {
for (int i = 0; i < K; i++)
if ((d >> i) & 1)
x = Jump[x][i];
return x;
}
}HLD;
int main() {
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
int n = read(0);
for (int i = 1; i < n; i++) {
int x = read(0), y = read(0);
HLD.connect(x, y);
}
HLD.Deep[0] = -1;
HLD.dfs1(1, 0);
HLD.dfs2(1, 0);
HLD.prepare(n);
for (int i = 1; i <= n; i++) {
int d = read(0), y = HLD.Query(i, d);
if (!y) y = 1;
HLD.Modify(i, y, n);
}
for (int i = 1; i <= n; i++)
Sum[i] += Sum[i - 1];
for (int i = 1; i <= n; i++)
printf("%d ", Sum[HLD.Dfn[i]]);
putchar('\n');
return 0;
}
C.Forest
求给定图边集的所有子集的最小生成树森林边权之和。\(n\leqslant 16,m\leqslant 100\)
咕咕咕
D.Fourier and Theory for the Universe
集合中有整数1 ~ n,定义集合中一个数位"FEN",如果其满足:
- 它是两个质数的乘积
- 它是两个"FEN"数的乘积
求集合中"FEN"数的个数\((n\leqslant 10^{11})\)
一个数\(n=\prod\limits_{i=1}^kp_i^{\alpha_i}\)是"FEN"当且仅当\(\sum\limits_{i=1}^k\alpha_i \equiv 0\;(\%2)\)且\(2\max\{\alpha_1,\alpha_2,...,\alpha_k\}\leqslant\sum\limits_{i=1}^k\alpha_i\)
min25筛的本质是枚举所有的\(\prod\limits_{i=1}^kp_i^{\alpha_i}\),并快速计算\(q\prod\limits_{i=1}^kp_i^{\alpha_i}(p_1<p_2<...p_k<q)\)的贡献
在这里,如果\(\sum \alpha_i \equiv 0(\%2)\)且\(2\max\{\alpha_1,...,\alpha_k,1\}\leqslant \sum \alpha_i +1\),则贡献为\(p_{k+1}\)到\(\lfloor\frac{n}{\prod_{i=1}^kp_i^{\alpha_i}}\rfloor\)的质数数量,否则贡献为0
min25筛,咕咕咕
E.From AtCoder
给定一个\(n\times n\)的矩阵,每次操作可以选一行一列,这一行所有数增加\(x\),这一列所有数减少\(x\),问\(2n-2\)次操作能否将所有数变成非负?
设行\(i\)整体增加\(r_i\),列\(j\)整体减少\(c_j\),则限制为\(r_i+c_j\geqslant a_{i,j}\),这就是最小顶标和的形式,直接KM求出一则可行顶标即可
如果有\(k\)跳匹配边\((i,j)\)为0,不难构造出\(2n-1-k\)次操作的方案数,但不一定有0边,我们要制造0边。不妨设匹配边权为0,那么可以\(n-1\)次操作制造\(n\)条0边,总操作数\(2n-2\)
代码,咕咕咕
F.Hash
令\(P=998244353\),给出四个整数\(F(T),X,Y,Z\),其中\(X,Y,Z\)在\([2,P-2]\)中随机生成,定义一棵树的哈希值为\(\sum\limits_{i<j}X^iY^jZ^{\mathrm{lca}(i,j)}\%P\),需要构造出点数\(\leqslant 50\)的树满足哈希值等于\(F(T)\)
构造 + 搜索,略
G.Icon Design
大模拟题,题面略
/*program from Wolfycz*/
#include<map>
#include<set>
#include<cmath>
#include<cstdio>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
#define lMax 1e18
#define MK make_pair
#define iMax 0x7f7f7f7f
#define sqr(x) ((x)*(x))
#define pii pair<int,int>
#define UNUSED(x) (void)(x)
#define lowbit(x) ((x)&(-x))
using namespace std;
typedef long long ll;
typedef unsigned int ui;
typedef unsigned long long ull;
template<typename T>inline T read(T x) {
int f = 1; char ch = getchar();
for (; ch < '0' || ch>'9'; ch = getchar()) if (ch == '-') f = -1;
for (; ch >= '0' && ch <= '9'; ch = getchar()) x = (x << 1) + (x << 3) + ch - '0';
return x * f;
}
inline void print(int x) {
if (x < 0) putchar('-'), x = -x;
if (x > 9) print(x / 10);
putchar(x % 10 + '0');
}
int main() {
int n = read(0);
vector<vector<char>>Map(4 * n + 5, vector<char>(13 * n + 19, '.'));
for (int i = 0; i < 4 * n + 5; i++)
Map[i][0] = Map[i][13 * n + 18] = '*';
for (int j = 0; j < 13 * n + 19; j++)
Map[0][j] = Map[4 * n + 4][j] = '*';
//N
for (int i = n + 1; i < 3 * n + 4; i++)
Map[i][n + 2] = Map[i][3 * n + 4] = Map[i][i + 1] = '@';
//F
for (int i = n + 1; i < 3 * n + 4; i++)
Map[i][4 * n + 6] = Map[n + 1][3 * n + 5 + i] = Map[2 * n + 2][3 * n + 5 + i] = '@';
//L
for (int i = n + 1; i < 3 * n + 4; i++)
Map[i][7 * n + 10] = Map[3 * n + 3][6 * n + 9 + i] = '@';
//S
for (int i = n + 1; i < 3 * n + 4; i++)
Map[n + 1][9 * n + 13 + i] = Map[2 * n + 2][9 * n + 13 + i] = Map[3 * n + 3][9 * n + 13 + i] = '@';
for (int i = n + 1; i < 2 * n + 3; i++)
Map[i][10 * n + 14] = Map[i + n + 1][12 * n + 16] = '@';
for (int i = 0; i < 4 * n + 5; i++) {
for (int j = 0; j < 13 * n + 19; j++)
putchar(Map[i][j]);
putchar('\n');
}
return 0;
}
H.Jumping Steps
给定\(n\)级台阶,编号分别为\(1\sim n\),令初始位置为0,现在想要跳到\(n\)。其中有\(m\)个障碍物,\(0,n\)一定不是障碍物,任何时刻不得处于障碍物位置。每次跳跃可以从\(x\)跳到\(x+k(k>0)\),若跨越\(S\)个障碍物得0分,否则得\(k^2\)分,最终分数为每一步分数之和,问所有从0跳到\(n\)的不同方案书的分数之和?
咕咕咕
I.Line
给定\(n\)个向量,构造一个点集,使得点集中的任意一个点\((a_i,b_i)\),对于任意向量\((x_j,y_j)\),均有直线\((a_i+tx_j,b_i+ty_j)\)恰好经过\(d\)个点
如果\(n=1\),则是一条线\(n\)个点;如果\(n=2\),则是一个平行四边形\(d^2\)个点,从\(n-1\)到\(n\),可以将原来\(d^{n-1}\)个点按照\((x_n,y_n)\)平移\(d-1\)次,得到\(d^n\)个点
/*program from Wolfycz*/
#include<map>
#include<set>
#include<cmath>
#include<cstdio>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
#define lMax 1e18
#define MK make_pair
#define iMax 0x7f7f7f7f
#define sqr(x) ((x)*(x))
#define pii pair<int,int>
#define UNUSED(x) (void)(x)
#define lowbit(x) ((x)&(-x))
using namespace std;
typedef long long ll;
typedef unsigned int ui;
typedef unsigned long long ull;
template<typename T>inline T read(T x) {
int f = 1; char ch = getchar();
for (; ch < '0' || ch>'9'; ch = getchar()) if (ch == '-') f = -1;
for (; ch >= '0' && ch <= '9'; ch = getchar()) x = (x << 1) + (x << 3) + ch - '0';
return x * f;
}
inline void print(int x) {
if (x < 0) putchar('-'), x = -x;
if (x > 9) print(x / 10);
putchar(x % 10 + '0');
}
int gcd(int x, int y) { return !y ? x : gcd(y, x % y); }
int main() {
int n = read(0), d = read(0);
int G[10]; G[0] = 1;
for (int i = 1; i < 10; i++) G[i] = G[i - 1] * 23;
set<pii>vec;
vector<pii>Ans;
for (int i = 1; i <= n; i++) {
int x = read(0), y = read(0);
int c = gcd(x, y);
vec.insert(make_pair(x / c, y / c));
}
Ans.push_back(make_pair(0, 0));
int Times = -1;
for (auto now : vec) {
Times++;
vector<pii>temp = Ans;
for (auto p : temp)
for (int k = 1; k < d; k++)
Ans.push_back(make_pair(p.first + k * now.first * G[Times], p.second + k * now.second * G[Times]));
}
printf("%llu\n", Ans.size());
for (auto p : Ans)
printf("%d %d\n", p.first, p.second);
return 0;
}
J.Number Game
给三个整数\(A,B,C\),每次操作可以把\(B\)变为\(A-B\),或者把\(C\)变成\(B-C\),问\(C\)是否能变成\(x\)?
连续操作\(B\)或者\(C\)两次相当于没操作,考虑交叉操作,如果两个操作次数相等则\(C\)的可达集合\(S=\{x|x=C+k\times(A-2\times B)\}\),如果两次操作不等则\(C\)的可达集合\(S=\{x|x=B-C+k\times(A-2\times B)\}\),注意特判一下\(A=2B\)的情况
/*program from Wolfycz*/
#include<map>
#include<set>
#include<cmath>
#include<cstdio>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
#define lMax 1e18
#define MK make_pair
#define iMax 0x7f7f7f7f
#define sqr(x) ((x)*(x))
#define pii pair<int,int>
#define UNUSED(x) (void)(x)
#define lowbit(x) ((x)&(-x))
using namespace std;
typedef long long ll;
typedef unsigned int ui;
typedef unsigned long long ull;
template<typename T>inline T read(T x) {
int f = 1; char ch = getchar();
for (; ch < '0' || ch>'9'; ch = getchar()) if (ch == '-') f = -1;
for (; ch >= '0' && ch <= '9'; ch = getchar()) x = (x << 1) + (x << 3) + ch - '0';
return x * f;
}
inline void print(int x) {
if (x < 0) putchar('-'), x = -x;
if (x > 9) print(x / 10);
putchar(x % 10 + '0');
}
int main() {
int T = read(0);
while (T--) {
int A = read(0), B = read(0), C = read(0), x = read(0);
if (A == B << 1)
printf(C == x || B - C == x ? "Yes\n" : "No\n");
else {
bool Flag = 1;
Flag &= (bool)((x - C) % (A - (B << 1)));
Flag &= (bool)((x - B + C) % (A - (B << 1)));
printf(Flag ? "No\n" : "Yes\n");
}
}
return 0;
}
K.SolarPea and Inversion
对所有长度为\(n\),含有\(m\)个1,且满足\(k\)个形如第\(x\)位必须是\(y\)的限制的01序列,计算\(c^{逆序对数}\)的和
咕咕咕
L.Striking String Problem
给定字符串\(S,T\),正整数\(k\)和\(2k\)个整数\(l_i,r_i\),令\(U=S[l_1,r_1]+...+S[l_k,r_k]\),\(q\)次询问给定\(x,y\),问\(T\)在\(U[x,y]\)中出现的次数?
咕咕咕
M.Z-Game on grid
一个\(n\times n\)的网格,包含'A','B','.'三种字符,从\((1,1)\)出发,Alice和Bob轮流操作,Alice先手。在\((x,y)\)可以走到\((x+1,y)\)或\((x,y+1)\),如果走到'A'则Alice胜利,走到'B'则Bob胜利,否则平局,每次输出三个答案,问Alice是否能必赢,必平,必输
显然是博弈论问题,考虑DP,设\(F[i][j]\)表示Alice能否必胜,显然对于\((x+y)\%2=0\)的点,是Alice行动,其他点则是Bob行动。对Alice而言,只要\((x+1,y)\)或者\((x,y+1)\)的函数值为true,那么\(F[x][y]\)必然也是true;对Bob而言,如果\((x+1,y)\)或者\((x,y+1)\)的函数值为false,那么\(F[x][y]\)必然也是false(Alice想着赢,Bob想着输),那么我们从右下开始往左上转移即可
至于平局和输,改一下初值也是一样的
/*program from Wolfycz*/
#include<map>
#include<set>
#include<cmath>
#include<cstdio>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
#define lMax 1e18
#define MK make_pair
#define iMax 0x7f7f7f7f
#define sqr(x) ((x)*(x))
#define pii pair<int,int>
#define UNUSED(x) (void)(x)
#define lowbit(x) ((x)&(-x))
using namespace std;
typedef long long ll;
typedef unsigned int ui;
typedef unsigned long long ull;
template<typename T>inline T read(T x) {
int f = 1; char ch = getchar();
for (; ch < '0' || ch>'9'; ch = getchar()) if (ch == '-') f = -1;
for (; ch >= '0' && ch <= '9'; ch = getchar()) x = (x << 1) + (x << 3) + ch - '0';
return x * f;
}
inline void print(int x) {
if (x < 0) putchar('-'), x = -x;
if (x > 9) print(x / 10);
putchar(x % 10 + '0');
}
const int N = 5e2;
char Map[N + 10][N + 10];
bool F[N + 10][N + 10];
int main() {
int T = read(0);
while (T--) {
int n = read(0), m = read(0);
memset(F, 0x00, sizeof(F));
for (int i = 1; i <= n; i++) scanf("%s", Map[i] + 1);
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
F[i][j] = Map[i][j] == 'A';
for (int i = n; i; i--) {
for (int j = m; j; j--) {
if (Map[i][j] != '.' || (i == n && j == m)) continue;
if ((i + j) % 2 == 0)
F[i][j] = (i == n ? 0 : F[i + 1][j]) | (j == m ? 0 : F[i][j + 1]);
else
F[i][j] = (i == n ? 1 : F[i + 1][j]) & (j == m ? 1 : F[i][j + 1]);
}
}
printf(F[1][1] ? "yes " : "no ");
memset(F, 0x00, sizeof(F));
if (Map[n][m] != '.')
printf("no ");
else {
F[n][m] = 1;
for (int i = n; i; i--) {
for (int j = m; j; j--) {
if (Map[i][j] != '.' || (i == n && j == m)) continue;
if ((i + j) % 2 == 0)
F[i][j] = (i == n ? 0 : F[i + 1][j]) | (j == m ? 0 : F[i][j + 1]);
else
F[i][j] = (i == n ? 1 : F[i + 1][j]) & (j == m ? 1 : F[i][j + 1]);
}
}
printf(F[1][1] ? "yes " : "no ");
}
memset(F, 0x00, sizeof(F));
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
F[i][j] = Map[i][j] == 'B';
for (int i = n; i; i--) {
for (int j = m; j; j--) {
if (Map[i][j] != '.' || (i == n && j == m)) continue;
if ((i + j) % 2 == 0)
F[i][j] = (i == n ? 0 : F[i + 1][j]) | (j == m ? 0 : F[i][j + 1]);
else
F[i][j] = (i == n ? 1 : F[i + 1][j]) & (j == m ? 1 : F[i][j + 1]);
}
}
printf(F[1][1] ? "yes\n" : "no\n");
}
return 0;
}