IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 2021牛客多校第二场题解 -> 正文阅读

[数据结构与算法]2021牛客多校第二场题解

K题

题目大意:给出n,k,表示一共n个数,生成单调栈序列b,接下来k行每行输入p和v表示b[p] = v,请写出一个满足要求的序列。n<1e6。

思路:k可能小于n,那么将b数组都填满,按如下的规则:若当前b有值,则从此位置到前一个有值的b之间填充b[i]-1,b[i]-2…,最后一个有值的b右边都用最后一个b的值填充。比如已知b[2]=2,b[5]=4,则完整的填充序列为1,2,2,3,4。
接下来按从小到大,从右到左的原则排序并赋值。

ac代码:

#include <bits/stdc++.h>

using namespace std;

const int N = 5e6+6;
int b[N],a[N];
bitset<N> vis;
struct node{
	int id,v,ans;
	bool operator<(const node&t)const{
		if(v == t.v)return id > t.id;
		return v < t.v;
	}
}c[N];
bool cmp(node t1,node t2){
	return t1.id<t2.id;
}
int main(){
	int n,k;
	scanf("%d%d",&n,&k);
	for(int i = 1;i <= k;i++){
		int p,v;
		scanf("%d%d",&p,&v);
		b[p] = v,vis[p] = true;
	}
	for(int i = 1;i <= n;i++)
		if(vis[i])
			for(int j = i - 1;j >= 1&&!vis[j];j--)
				b[j] = max(1,b[j + 1] - 1);
	for(int i = 1;i <= n;i++)
		if(!b[i])b[i] = b[i - 1];
	int f = 0;
	for(int i = 2;i <= n;i++)	
		if(b[i] >1 + b[i - 1]){
			f = 1;
			break;
		}
	if(b[1]>1)f = 1;
	if(f){
		cout << "-1" << endl;
	}
	else{
		for(int i = 1;i <= n;i++)
			c[i].id = i,c[i].v = b[i];
		sort(c+1,c+n+1);
		int idx = 1;
		for(int i = 1;i <= n;i++)c[i].ans = idx++;
		sort(c+1,c+1+n,cmp);
		for(int i = 1;i <= n;i++)printf("%d ",c[i].ans);
		printf("\n");
	}
	return 0;
}

p.s. 当时没有想到填满b数组,其实如果不填满b数组,b[2]=2和b[2]=3得到的序列可能一样,这并不是我们想要的答案。

J题

题目大意:t组输入,每组给出s,k,p,有s个数,求所有大小为k的子集中,每个子集的所有元素的最大公约数,输出它们的乘积。t<=60,s<=4e4,k<=30,1e6<=p<=1e14.

思路:用容斥原理求出每个数作为最大公约数可以出现在几个集合中。如i作为最大公约数出现在ki个集合中,则本题要求的是∏(i=1,i=maxn)(i ^ ki),其中maxn为s个数中的最大值。由于p较大且不一定为质数,考虑用欧拉降幂(a ^ b(mod m)=a ^ (b mod phi + phi) mod m),其中phi为b的欧拉函数值。

ac代码(玄学,同样的代码有可能1001ms也有可能800ms,看评测机发挥了)

#include <bits/stdc++.h>

using namespace std;

const int N = 8e4+4;

typedef long long LL;

LL cnt[N];
LL c[N][35],dp[N];
LL S,k,res,phi;
int T;
LL P;
LL total = 0,factor[100];
//LL euler_phi(LL n) {
//  LL ans = n;
//  for (LL i = 2; i * i <= n; i++)
//    if (n % i == 0) {
//      ans = ans / i * (i - 1);
//      while (n % i == 0) n /= i;
//    }
//  if (n > 1) ans = ans / n * (n - 1);
//  return ans;
//}

LL ksc(LL a, LL b, LL mod) {
	return ((a * b - (long long)((long long)((long double)a / mod * b + 1e-3) * mod)) % mod + mod) % mod;
}
LL gcd(LL a,LL b){
	return b==0?a:gcd(b,a%b);
}
//LL ksc(LL a,LL b,LL c){
//	LL res = 0;
//	while(b){
//		if(b&1)res = (res + a)%c;
//		a = (a + a)%c;
//		b>>=1;
//	}
//	return res%c;
//}
LL ksm(LL a,LL b,LL c){
	LL res = 1;
	while(b){
		if(b&1)res =ksc(res,a,c);
		b >>= 1;
		a = ksc(a,a,c);
	}
	return res%c;
}
//LL ksm(LL a,LL b,LL c){
//	LL res = 1;
//	while(b){
//		if(b&1)res = ksc(res,a,c);
//		b >>= 1;
//		a = ksc(a,a,c);
//	}
//	return res%c;
//}


int a[] = { 2, 3, 5, 7, 11 };
bool miller_rabin(LL n) {
	if (n == 1) return 0;
	for (int i = 0; i < 5; ++i) {
		if (n == a[i]) return 1;
		if (!(n % a[i])) return 0;
	}
	LL d = n - 1;
	while (!(d & 1)) d >>= 1;
	for (int i = 1; i <= 5; ++i) {
		LL a = rand() % (n - 2) + 2;
		bool tmp_k = false;
		LL tmp_d = d;
		LL tmp = ksm(a, tmp_d, n);
		if (tmp == 1)	tmp_k = true;
		// 先把所有的2给提出来,然后在一个一个乘上去,这样比直接做快
		while (tmp != 1 && tmp != n - 1 && tmp_d != n - 1) {
			tmp = ksc(tmp, tmp, n);
			tmp_d <<= 1;
		}// 二次探测
		if (tmp == n - 1)	tmp_k = true;

		if (!tmp_k)
			return 0;
	}
	return 1;
}
// 找出n的一个因数
const int M = (1 << 7) - 1;// 一个玄学值

LL pollard_rho(LL n) {
	for (int i = 0; i < 5; ++i) if (n % a[i] == 0) return a[i];
	LL x = rand(), y = x, t = 1, a = rand() % (n - 2) + 2;
	for (int k = 2; ; k <<= 1, y = x) {
		LL q = 1;
		// k用于倍增
		for (int i = 1; i <= k; ++i) {
			x = (ksc(x, x, n) + a) % n;// f(x) = x^2+a
			q = ksc(q, abs(x - y), n);// 每一次的|x-y|累加
			// 如果次数超过M
			if (!(i & M)) {
				t = gcd(q, n);
				if (t > 1) break;
			}
		}
		if (t > 1 || (t = gcd(q, n)) > 1) break;
	}
	return t;
}
// 找出x的所有因数
void find(LL x) {
	if (x == 1 || x <= 0) return;
	if (miller_rabin(x)) {
		factor[++total] = x;
		return;
	}
	LL p = x;
	while (p == x) p = pollard_rho(x);
	while (x % p == 0) x /= p;
	find(p);// 递归遍历所有的因数
	find(x);
}
LL C(LL n,LL k){
	if (n < k)return 0;
	return c[n][k];
}
inline LL read() {
	LL s = 0;
	char ch = getchar();
	while (ch < 48 || ch>57)ch = getchar();
	while (ch > 47 && ch < 58)s = (s << 1) + (s << 3) + (ch ^ 48), ch = getchar();
	return s;
}
int main(){
//	scanf("%d",&T);
	T = read();
	while(T--){
		memset(cnt,0,sizeof cnt);		
//		scanf("%lld%lld%lld",&S,&k,&P);
		S = read(),k = read(),P = read();
		int maxn = 0;
		for(int i = 1;i <= S;i++){
			int tm;
//			scanf("%d",&tm);
			tm = read();
			cnt[tm]++;
			maxn = max(maxn,tm);
		}
		res = 1;
		total = 0;
		find(P);// 寻找p的约数
		phi = P;// 计算phi(p)
		for (int i = 1; i <= total; i++) {
			phi = phi / factor[i] * (factor[i] - 1);
		}
		c[0][0] = 1;
		for (int i = 1; i <= S; i++) {
			c[i][0] = 1;
			if (i <= 31)	c[i][i] = 1;
			// k的值不会超过30,不需要计算更多位
			for (int j = 1; j < i && j <= 31; j++) {
				c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]);// 组合数的递推公式
				while (c[i][j] - phi >= phi) c[i][j] -= phi;
			}

		}
//		for (int i = 0; i <= S; i ++ )
//	        for (int j = 0; j <= 30&&j<=i; j ++ )
//	            if (!j) c[i][j] = 1;
//	            else c[i][j] = (c[i - 1][j] + c[i - 1][j - 1])%phi;
		for(int i = maxn;i >= 1;i--){
			int tp = 0;
			for(int j = i;j <= maxn;j+=i){
				tp+=cnt[j];
			}
			dp[i] = C(tp,k)%phi;
			for(int j = i + i;j <= maxn;j+=i){
				dp[i]-=dp[j];
			}
			if(dp[i]<0)dp[i] = (dp[i]%phi + phi)%phi;
			if(dp[i]>phi)res = ksc(res,(ksm(i,dp[i]%phi+phi,P)),P);
			else res = ksc(res,(ksm(i,dp[i],P)),P);		
		}
		printf("%lld\n",res);
	}
	return 0;
}

p.s. 真的是一言难尽,从写完第一份到debug完,前前后后四个小时。factor数组记得开long long;快速乘的玄学写法,很快;米勒罗宾素数筛当板子用了,求某个大数的欧拉函数;大体思路都没问题了就慢慢调整细节,尝试各种写法,说不定就快个几十ms就卡过了。

F题

题目大意:给出三维的四个点ABCD的坐标和k1,k2,要求求出同时满足|AP|>=k1|BP|,|CP|>=k2|DP|的点P的可取的区域的体积。

思路:推式子,设A(x1,y1,z1),B(x2,y2,z2),p(x,y,z),则有(x-x1)2+(y-y1)2+(z-z1)2>=k12[(x-x2)2+(y-y2)2+(z-z2)2],整理可得(k12 - 1)(x2 + y2 + z2)-(2k12x2 - 2x1)x - (2k12y2 - 2y1)y - (2k12z2 - 2z1)z <= 0,我们发现这是形如x2+y2+z2+Ax+By+Cz+D<=0的球面方程,而该方程的几何意义是P为该球体内部(含边界)的点。该球体半径为sqrt((A2 + B2 + C2 - 4*D)/4),球心为(-A/2,-B/2,-C/2)。接下来分情况讨论:两球相切、包含、相交。

ac代码:

#include <bits/stdc++.h>

using  namespace std;

const int N = 1010;
const double pi = acos(-1);
int t;
double x[4],y[4],z[4],k1,k2;
int main(){
	scanf("%d",&t);
	while(t--){
		for(int i = 0;i < 4;i++)scanf("%lf%lf%lf",&x[i],&y[i],&z[i]);
		scanf("%lf%lf",&k1,&k2);
		double k11 = k1*k1-1,c1x,c1y,c1z,r1;
		c1x = (k1*k1*x[1]-x[0])/k11,c1y = (k1*k1*y[1]-y[0])/k11,c1z = (k1*k1*z[1]-z[0])/k11;
		r1 = sqrt(c1x*c1x+c1y*c1y+c1z*c1z-(k1*k1*((x[1]*x[1])+(y[1]*y[1])+(z[1]*z[1]))-x[0]*x[0]-y[0]*y[0]-z[0]*z[0])/k11);
		double k22 = k2*k2-1,c2x,c2y,c2z,r2;
		c2x = (k2*k2*x[3]-x[2])/k22,c2y = (k2*k2*y[3]-y[2])/k22,c2z = (k2*k2*z[3]-z[2])/k22;
		r2 = sqrt(c2x*c2x+c2y*c2y+c2z*c2z-(k2*k2*((x[3]*x[3])+(y[3]*y[3])+(z[3]*z[3]))-x[2]*x[2]-y[2]*y[2]-z[2]*z[2])/k22);
		double dis = sqrt((c1x-c2x)*(c1x-c2x)+(c1y-c2y)*(c1y-c2y)+(c1z-c2z)*(c1z-c2z));
		double ans = 0.000;
		if(dis>=r1+r2)ans = 0;
		else if(dis + r1 <= r2)ans = (4.000/3.000)*pi*r1*r1*r1;
		else if(dis + r2 <= r1)ans = (4.000/3.000)*pi*r2*r2*r2;
		else{
			double h1 = r1*(1-(r1*r1+dis*dis-r2*r2)/(2.000*dis*r1));//余弦定理求角度,再算h
			double h2 = r2*(1-(r2*r2+dis*dis-r1*r1)/(2.000*dis*r2));
			ans+=(1.000/3.000)*pi*((3.000*r1-h1)*h1*h1+(3.000*r2-h2)*h2*h2); 
		}
		printf("%.3f\n",ans);
	}
	return 0;
}

p.s. 赛场上没来得及看这个题…补题的时候感觉挺可做的。学习了球缺的计算公式:V=pih2(3R-h)/3,其中h为球缺(那个小片)的高,R为球的半径。注意求h的时候要用余弦定理间接求一下,不能草率的直接用(r1+r2-dis)/2,因为球的半径是不一定一样大,不一定能均分滴~

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2021-08-07 21:48:54  更:2021-08-07 21:49:22 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 19:36:58-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码