ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

"蔚来杯"2022牛客暑期多校训练营1

2022-08-02 01:31:08  阅读:102  来源: 互联网

标签:10 ch int 蔚来 多校 long 牛客 include define


A.Villages: Landlin

数轴上有1个发电站和n-1个建筑,发电站位于\(x_s\)位置,能够与距离\(r_s\)以内的建筑相连。第\(i\)个建筑位于\(x_i\),能与距离\(r_i\)以内的电线杆直接相连。电线杆之间相连需要使用电线,问最少需要多长的电线可以使所有建筑都有能源?

(注意建筑可以传递能量)

这题相当于有n个区间\([x_s-r_s,x_s+r_s],[x_i-r_i,x_i+r_i]\),若区间交集非空则相交。问使得区间全部相交所需要添加的最小区间长度。我们将数据读入,按左端点排序,扫描时不断更新右端点,需要添加区间时更新答案即可。

/*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 = 2e5;
struct Segment {
	int l, r;
	Segment(int _l = 0, int _r = 0) { l = _l, r = _r; }
	bool operator<(const Segment& ots)const { return l < ots.l; }
};
int main() {
	//	freopen(".in","r",stdin);
	//	freopen(".out","w",stdout);
	int n = read(0);
	vector<Segment>segments;
	for (int i = 1; i <= n; i++) {
		int x = read(0), radius = read(0);
		segments.push_back(Segment(x - radius, x + radius));
	}
	sort(segments.begin(), segments.end());
	ll Ans = 0, MaxR = -lMax;
	bool Flag = 0;
	for (auto segment : segments) {
		if (Flag && MaxR < segment.l)
			Ans += segment.l - MaxR;
		MaxR = max(MaxR, 1ll * segment.r), Flag |= 1;
	}
	printf("%lld\n", Ans);
	return 0;
}

B.Spirit Circle Observation

给定长度为\(n\)的字符串s,求满足条件的二元组(A,B)的个数

  • A,B是s的子串
  • A,B长度相同
  • A+1=B(数字意义上)

即使两个子串相同,只要它们的位置不同便认为是不同子串

\(1\leqslant n\leqslant 4\times 10^5\)

字符串难难,咕咕咕

C.Grab the Seat!

有一个二维平面,屏幕是线段\((0,1)\sim (0,m)\),有\(n\times m\)个座位,有\(k\)个人在座位上,第\(i\)个人坐标为\((x_i,y_i)\)。有\(q\)次操作,每次修改一个人的坐标后,求到屏幕视线不被任何人挡住的座位个数

对于每个人而言,他们所挡住的位置是起点为(0,1),(0,m)的两条射线在该点处相交后之间的区域。如果我们对于每个点求出这些挡住区域的并集即可求出答案。

这样的区域实际上构成了一个折线图,对于每个\(y\)都存在一个分界点\(t\),满足\(x\in[1,t)\)是合法的,\(x\in[t,n]\)则是非法的。

考虑如何维护这样一个折线图,实际上每条折线线段的延长线都是经过屏幕两端的,故我们将其分成两类,如果按照\(y\)降序或者升序依次加入点,不难发现,一旦高斜率的线段加入,便会碾压低斜率的线段,故我们对\(y\)枚举一遍,维护最大斜率即可

/*program from Wolfycz*/
#include<map>
#include<set>
#include<cmath>
#include<cstdio>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<unordered_set>
#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 = 2e5;
unordered_set<int>points[N + 10];
int Row[N + 10];
pii A[N + 10];
bool Check(pii A, pii B) { return 1ll * B.second * A.first > 1ll * A.second * B.first; }
int main() {
	//	freopen(".in","r",stdin);
	//	freopen(".out","w",stdout);
	int n = read(0), m = read(0), k = read(0), q = read(0);
	for (int i = 1; i <= k; i++) {
		int x = read(0), y = read(0);
		points[y].insert(x);
		A[i] = MK(x, y);
	}
	for (int i = 1; i <= q; i++) {
		int p = read(0);
		points[A[p].second].erase(A[p].first);
		int x = read(0), y = read(0);
		A[p] = MK(x, y);
		points[y].insert(x);
		pii Now = MK(0, 0);
		for (int j = 1; j <= m; j++) {
			if (j == 1) {
				Row[j] = n + 1;
				for (auto p : points[j])
					Row[j] = min(Row[j], p);
				continue;
			}
			for (auto p : points[j])
				if (!Now.second || Check(Now, MK(p, j - 1)))
					Now = MK(p, j - 1);
			Row[j] = !Now.second ? n + 1 : (int)ceil(1.0 * (j - 1) * Now.first / Now.second);
		}

		Now = MK(0, 0);
		for (int j = m; j >= 1; j--) {
			if (j == m) {
				Row[j] = min(Row[j], n + 1);
				for (auto p : points[j])
					Row[j] = min(Row[j], p);
				continue;
			}
			for (auto p : points[j])
				if (!Now.second || Check(Now, MK(p, m - j)))
					Now = MK(p, m - j);
			Row[j] = min(Row[j], min(!Now.second ? n + 1 : (int)ceil(1.0 * (m - j) * Now.first / Now.second), n + 1));
		}

		ll Ans = 0;
		for (int j = 1; j <= m; j++)
			Ans += Row[j] - 1;
		printf("%lld\n", Ans);
	}
	return 0;
}

D.Mocha and Railgun

给定一个圆和严格圆内一点\(p\),以\(p\)为中点发射长度为\(2d\)的电磁炮,已知\(p\)到圆周距离严格小于\(d\),问最大能摧毁的圆弧长度?

几何题,手画后不难发现,当发射基座位于线段\(Op\)上时,可以摧毁的圆弧最长

/*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() {
	//	freopen(".in","r",stdin);
	//	freopen(".out","w",stdout);
	int T = read(0);
	while (T--) {
		double radius = read(0), x = read(0), y = read(0), d = read(0);
		double distance = sqrt(sqr(x) + sqr(y));
		double alpha = acos((distance - d) / radius);
		double beta = acos((distance + d) / radius);
		double len = (alpha - beta) * radius;
		printf("%.10lf\n", len);
	}
	return 0;
}

E.LTCS

定义一棵带点权的有根树\(T_a\)是\(T_b\)的子序列当且仅当:

  • \(T_a\)的点到\(T_b\)的点存在一个单射\(F\)
  • 对于\(T_a\)中所有的点有\(c_{a,u}=c_{b,F(u)}\)
  • 如果\(u\)在\(T_a\)中是\(v\)的祖先,则\(F(u)\)在\(T_b\)中是\(F(v)\)的祖先
  • 如果\(u\)在\(T_a\)中是\(v,w\)的父亲,则在\(T_b\)中\(F(u)\)在\(F(v),F(w)\)的简单路径上

求两棵以1为根的树\(T_1,T_2\)的最大公共子序列的大小

dp+二分图匹配,咕咕咕

F.Cut

给定1到\(n\)的排列\(a_1,a_2,...,a_n\),有\(m\)次以下三种操作:

  • 将\(a_l,a_{l+1},...,a_r\)升序排序
  • 将\(a_l,a_{l+1},...,a_r\)降序排序
  • 询问\(a_l,a_{l+1},...,a_r\)中最长的奇偶交替子序列

\(1\leqslant n,m\leqslant 10^5\)

线段树合并,咕咕咕

G.Lexicographical Maximum

给定\(n\),求\(1\sim n\)中字典序最大的字符串

显然,答案除去最后一位则全为9(也可能为空)。故对\(n\)进行判断,若\(n\)除去最后一位均为9,则输出\(n\);否则输出\(|n|-1\)个9

(代码略)

H.Fly

\(n\)种物品每种有无限个,第\(i\)个物品的体积为\(a_i\),求解选择物品总体积不超过\(M\)的方案数

此外存在\(k\)个限制,第\(i\)个限制形如第\(b_i\)个物品的所选数量二进制表示从高到低的低\(c_i\)位必须为0

\(1\leqslant n,a_i,\sum a_i\leqslant 10^4\),\(0\leqslant M\leqslant 10^{18}\),\(1\leqslant k\leqslant 5\times 10^3\)

DP + 多项式,咕咕咕

I.Chiitoitsu

初始有13张麻将牌,相同牌至多出现两次。每次从牌堆摸牌,若凑成七对子可直接胡牌,否则将其替换手里的任意一张牌或者直接打出。问在最优策略下,将手牌摸成七对子的期望轮数

首先明确一点,用摸到的牌替换手里的牌一定不会使答案更优,除非手里已经有一张一样的牌;其次,一旦有一对相同的牌在手中,我们边不再动它,故实际上摸牌轮数是由手中的单牌数决定的

此外,在最优策略下,手中的单牌必定在牌堆中还存有3个

考虑DP,设\(F[i][j]\)表示手中有\(i\)个单牌,牌堆还剩\(j\)张牌,将手中的牌摸成对子所需要的期望轮数,则转移方程为:

\[F[i][j]=\frac{3i}{j}\times F[i-2][j-1]+\frac{j-3i}{j}\times F[i][j-1]+1 \]

前者为摸到手中存在的单牌的情况,后者为没有摸到手中单牌的情况。注意当手上仅剩一张牌时,前面的状态就不需要考虑了

最后我们输出\(F[c][136-13]\)即可,\(c\)为初始手中的单牌数量

/*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 = 34, P = 1e9 + 7;
int F[N + 10][(N << 2) + 10], Inv[(N << 2) + 10];
void prepare() {
	Inv[0] = Inv[1] = 1;
	for (int i = 2; i <= N << 2; i++)	Inv[i] = 1ll * (P - P / i) * Inv[P % i] % P;
	//for (int i = 1; i <= N << 2; i++)	F[0][i] = 1;
	for (int i = 1; i <= N; i += 2) {
		for (int j = i * 3; j <= N << 2; j++) {
			int temp = i == 1 ? 0 : F[i - 2][j - 1];
			F[i][j] = 3ll * i % P * Inv[j] % P * temp % P;
			if (j > i * 3)
				F[i][j] = (F[i][j] + 1ll * (j - 3 * i) * Inv[j] % P * F[i][j - 1] % P) % P;
			(++F[i][j]) %= P;
		}
	}
}
int main() {
	//	freopen(".in","r",stdin);
	//	freopen(".out","w",stdout);
	prepare();
	int T = read(0);
	for (int Time = 1; Time <= T; Time++) {
		printf("Case #%d: ", Time);
		char s[30];
		scanf("%s", s);
		int len = strlen(s);
		map<string, int>msi;
		for (int i = 0; i < len; i += 2) {
			string temp;
			temp += s[i], temp += s[i + 1];
			msi[temp]++;
		}
		int Cnt = 0;
		for (auto p : msi)
			Cnt += p.second == 1;
		printf("%d\n", F[Cnt][(N << 2) - 13]);
	}
	return 0;
}

J.Serval and Essay

给定一张\(n\)个点\(m\)条边的无重边无自环的有向图,初始可选择一个点染黑,若一个点的入点全都染黑则该点也可以染黑,求最大化黑点数

考虑通过\(x\)确定\(y\)这种关系将\(x,y\)合并,如果\(x\)能够将\(y\)染色,那么我们就不必再考虑\(y\)了,将所有\(y\)指出的边改为\(x\)指出即可

当\(x,y\)合并后,原本\(y\)指向的边就变成了\(x\)指向,如果两者指向的边在\(t\)处重合,便会合并出很多\(x\ \mathrm{to}\ t\)的边,我们维护一个set用以自动去重;此外,这个时候的\(t\)也是被\(x\)所决定的,因此我们若在合并\(y\)时出现这种情况,\(t\)也是需要继续合并的

合并次数显然是\(O(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');
}
const int N = 2e5;
int Fa[N + 10], Sz[N + 10];
set<int>Frm[N + 10], Nxt[N + 10];
int Find(int x) { return x == Fa[x] ? x : Fa[x] = Find(Fa[x]); }
void Merge(int x, int y) {
	x = Find(x), y = Find(y);
	if (x == y)	return;
	if (Nxt[x].size() < Nxt[y].size())	swap(x, y);
	Sz[Fa[y] = x] += Sz[y];
	vector<pair<int, int>>temp;
	for (auto p : Nxt[y]) {
		Nxt[x].insert(p);
		Frm[p].erase(y);
		Frm[p].insert(x);
		if (Frm[p].size() == 1)
			temp.push_back(make_pair(x, p));
	}
	for (auto [x, y] : temp)
		Merge(x, y);
}
int main() {
	//	freopen(".in","r",stdin);
	//	freopen(".out","w",stdout);
	int T = read(0);
	for (int Case = 1; Case <= T; Case++) {
		int n = read(0);
		for (int i = 1; i <= n; i++)	Sz[Fa[i] = i] = 1;
		for (int i = 1; i <= n; i++) {
			int k = read(0);
			for (int j = 1; j <= k; j++) {
				int x = read(0);
				Frm[i].insert(x);
				Nxt[x].insert(i);
			}
		}
		for (int i = 1; i <= n; i++)
			if (Frm[i].size() == 1)
				Merge(*Frm[i].begin(), i);
		int Ans = 0;
		for (int i = 1; i <= n; i++) {
			Ans = max(Ans, Sz[i]);
			Frm[i].clear();
			Nxt[i].clear();
		}
		printf("Case #%d: %d\n", Case, Ans);
	}
	return 0;
}

K.Villages: Landcircles

给定二维平面\(n\)个圆,可在圆外任意处添加额外的点,连接点与点,点与圆,圆与圆的花费为所连线段长度,询问将\(n\)个圆连通的最小费用

防AK题,神仙知识,咕咕咕咕咕咕

标签:10,ch,int,蔚来,多校,long,牛客,include,define
来源: https://www.cnblogs.com/Wolfycz/p/16542396.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有