"蔚来杯"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;
}
posted @ 2022-09-02 23:26  Wolfycz  阅读(45)  评论(0编辑  收藏  举报