2022牛客寒假算法基础集训营4

比赛链接

2022牛客寒假算法基础集训营4

D.雪色光晕

题目描述

给出两个初始点,一个点动 n 次,另外一个点不动,给出动点的方向向量 (dx,dy),求动点和静点的最短距离

输入描述:

第一行是一个正整数 n
第二行是四个整数 x0y0xy ,用空格隔开。用来表示动点和静点的初始坐标。
接下来的n行,每行输入两个整数 xiyi,用来表示方向向量坐标。

数据范围:

1n200000
109x,y,xi,yi109

输出描述:

最近的距离。如果你的答案和正确答案的相对误差不超过 107,则认为答案正确。

示例1

输入

1 1 1 1 2 2 0

输出

1.0

示例2

输入

2 0 0 1 1 1 0 1 1

输出

0.70710678

示例3

输入

1 -10 0 1 1 20 0

输出

1.0

解题思路

计算几何
点到直线的距离公式:
设直线 L 的方程为Ax+By+C=0,点 P 的坐标为x0,y0,则点 P 到直线 L 的距离为:Ax0+By0+CA2+B2
同理可知,当Px0,y0,直线L的解析式为y=kx+b时,则点P到直线L的距离为:|kx0y0+b|k2+1

求出静点到 n 个线段的最小值即可

  • 时间复杂度:O(n)

代码

// Problem: 雪色光晕 // Contest: NowCoder // URL: https://ac.nowcoder.com/acm/contest/23479/D // Memory Limit: 524288 MB // Time Limit: 2000 ms // // Powered by CP Editor (https://cpeditor.org) // %%%Skyqwq #include <bits/stdc++.h> #define pb push_back #define fi first #define se second #define mkp make_pair using namespace std; typedef long long LL; typedef pair<int, int> PII; template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; } template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; } template <typename T> void inline read(T &x) { int f = 1; x = 0; char s = getchar(); while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); } while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar(); x *= f; } double x,y,xx,yy; int n; double dis(double x,double y,double xx,double yy) { return sqrt((x-xx)*(x-xx)+(y-yy)*(y-yy)); } double f(double dx,double dy) { double xe=x+dx,ye=y+dy; double res=min(dis(x,y,xx,yy),dis(xe,ye,xx,yy)); double k=dy/dx,b=y-k*x,bb=yy+1/k*xx; double xj=(bb-k*b)/(k*k+1); if(xj>=min(x,xe)&&xj<=max(x,xe))res=min(res,fabs(k*xx-yy+b)/sqrt(k*k+1)); return res; } int main() { scanf("%d",&n); scanf("%lf%lf%lf%lf",&x,&y,&xx,&yy); double res=dis(x,y,xx,yy); while(n--) { double dx,dy; scanf("%lf%lf",&dx,&dy); res=min(res,f(dx,dy)); x+=dx,y+=dy; } printf("%lf",res); return 0; }

G.子序列权值乘积

题目描述

小红定义一个数组的权值为该数组的最大值乘以最小值。例如数组 [4,1,3] 的权值是 41=4
小红拿到了一个数组。她想知道,这个数组的所有 非空子序列 的权值的乘积是多少?由于该数过大,请对1000000007取模。
子序列的定义:对于一个数组,删除其中某些数之后(也可以不删)得到的数组。子序列中的数的相对顺序必须和原数组中的顺序相同。
例如:数组 [1,3,2] 的非空子序列有 [1][3][2][1,3][1,2][3,2][1,3,2]7个。

输入描述:

第一行输入一个正整数 n ,代表数组的长度。
第二行输入 n 个正整数 ai,代表小红拿到的数组。

数据范围:

1n200000
1ai109

输出描述:

数组所有子序列的权值的乘积。答案对1000000007取模。

示例1

输入

2 2 3

输出

216

说明

对于子序列 [2,3] ,其权值为 32=6
对于子序列 [2] ,其权值为 22=4
对于子序列 [3] ,其权值为 33=9
因此所有非空子序列的权值乘积为: $6 * 4 * 9 = 216¥

示例2

输入

4 4 1 4 3

输出

757784222

解题思路

欧拉降幂:若正整数 a,n 互质,则对于任何正整数 b,有 ababmodφ(n)(modn)

由于是子序列,我们考虑每个值对答案的贡献,将数组排序并不会影响答案,对某个值 ai,其作为最小值时,后面的数即更大的数不能取否则与最小值矛盾,前面的数可以任取,即有 i1 个数可取可不取,共 2i1 种方案,同理,后面 ni 个数有 2ni 种方案,共 2i1+2ni 种方案,其对答案的贡献为 ai2i1+2ni,单单算的话由于指数过大会超时,可以欧拉降幂: ai2i1+2ni=ai(2i1+2ni)modφ(1e9+7)

  • 时间复杂度:O(n(logn+log(1e9+7)))

代码

// Problem: 子序列权值乘积 // Contest: NowCoder // URL: https://ac.nowcoder.com/acm/contest/23479/G // Memory Limit: 524288 MB // Time Limit: 2000 ms // // Powered by CP Editor (https://cpeditor.org) // %%%Skyqwq #include <bits/stdc++.h> #define pb push_back #define fi first #define se second #define mkp make_pair using namespace std; typedef long long LL; typedef pair<int, int> PII; template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; } template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; } template <typename T> void inline read(T &x) { int f = 1; x = 0; char s = getchar(); while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); } while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar(); x *= f; } const int N=2e5+5,mod=1e9+7; int n,a[N]; int ksm(int a,int b,int p) { int res=1%p; for(;b;b>>=1) { if(b&1)res=1ll*res*a%p; a=1ll*a*a%p; } return res; } int main() { scanf("%d",&n); for(int i=1;i<=n;i++)scanf("%d",&a[i]); sort(a+1,a+1+n); int res=1; for(int i=1;i<=n;i++) res=(1ll*res*ksm(a[i],(ksm(2,i-1,mod-1)+ksm(2,n-i,mod-1))%(mod-1),mod))%mod; printf("%d",res); return 0; }

I.爆炸的符卡洋洋洒洒

题目描述

给出 n 个物品体积 ai 和价值 bi,各物品最多只能选择一次,要求选出的物品的体积为 k 的倍数,求最大价值

输入描述:

第一行输入两个正整数 nk ,用空格隔开。
接下来的 n 行,每行输入两个正整数 aibi,用空格隔开。

数据范围:

1n,k1000
1ai,bi109

输出描述:

体积无法形成倍数关系,则输出1
否则输出最大价值。

示例1

输入

2 3 1 2 2 1

输出

3

示例2

输入

2 2 1 2 2 1

输出

1

示例3

输入

3 4 1 2 5 3 1 4

输出

-1

解题思路

01背包变形

背包体积过大,但是 k 较小,可将体积对 k 取模,将体积转化为模,将要求的体积转化为模为 0,即:

  • 状态表示:f[i][j] 表示前 i 个物品体积对 k 取模为 j 时的最大价值
  • 状态计算:f[i][j]=max(f[i1][j],f[i1][(jv[i]%k+k)%k]+w[i])

注意:初始化要尽可能小,表示取不到,f[0][0] 表示 0 个物品价值为 0

  • 时间复杂度:O(nk)

代码

// Problem: 爆炸的符卡洋洋洒洒 // Contest: NowCoder // URL: https://ac.nowcoder.com/acm/contest/23479/I // Memory Limit: 524288 MB // Time Limit: 2000 ms // // Powered by CP Editor (https://cpeditor.org) // %%%Skyqwq #include <bits/stdc++.h> #define pb push_back #define fi first #define se second #define mkp make_pair using namespace std; typedef long long LL; typedef pair<int, int> PII; template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; } template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; } template <typename T> void inline read(T &x) { int f = 1; x = 0; char s = getchar(); while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); } while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar(); x *= f; } const int N=1010; LL f[N][N]; int n,k,v[N],w[N]; int main() { scanf("%d%d",&n,&k); for(int i=1;i<=n;i++)scanf("%d%d",&v[i],&w[i]); for(int i=0;i<=n;i++)for(int j=0;j<=k;j++)f[i][j]=-1e12; f[0][0]=0; for(int i=1;i<=n;i++) for(int j=0;j<k;j++) f[i][j]=max(f[i-1][j],f[i-1][(j-v[i]%k+k)%k]+w[i]); printf("%lld",f[n][0]<=0?-1:f[n][0]); return 0; }

J.区间合数的最小公倍数

题目描述

给定一个区间 [l,r],求其中所有合数的最小公倍数

输入描述:

两个正整数 lr ,用空格隔开。

数据范围:1lr30000

输出描述:

若区间 [l,r] 中没有任何合数,则输出1
否则输出区间 [l,r] 所有合数的最小公倍数,答案对1000000007取模。

示例1

输入

2 3

输出

-1

说明

区间 [2,3] 的两个数 23 都是素数,不是合数。

示例2

输入

4 6

输出

12

说明

区间[4,6]中有三个数:456,其中 5 是素数, 46 是合数,它们的最小公倍数是12

示例3

输入

25000 30000

输出

187554966

解题思路

数学:求取多个数的最小公倍数,即将所有数分解质因数,统计每个素数出现的最高次幂,其乘积即为所求
例:a=233551b=243152,那么它们的最小公倍数就是 243552

直接欧拉筛求素数,剩余的合数求最小公倍数即可

  • 时间复杂度:O(nlogn)

代码

// Problem: 区间合数的最小公倍数 // Contest: NowCoder // URL: https://ac.nowcoder.com/acm/contest/23479/J // Memory Limit: 524288 MB // Time Limit: 2000 ms // // Powered by CP Editor (https://cpeditor.org) // %%%Skyqwq #include <bits/stdc++.h> #define pb push_back #define fi first #define se second #define mkp make_pair using namespace std; typedef long long LL; typedef pair<int, int> PII; template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; } template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; } template <typename T> void inline read(T &x) { int f = 1; x = 0; char s = getchar(); while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); } while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar(); x *= f; } const int N=3e4+5,mod=1e9+7; bool st[N]; int prime[N],v[N]; int l,r,m; void primes(int n) { memset(v,0,sizeof v); for(int i=2;i<=n;i++) { if(v[i]==0) { prime[++m]=i; v[i]=i; st[i]=true; } for(int j=1;j<=m;j++) { if(i*prime[j]>n||v[i]<prime[j])break; v[i*prime[j]]=prime[j]; } } } int ksm(int a,int b,int p) { int res=1; for(;b;b>>=1) { if(b&1)res=1ll*res*a%p; a=1ll*a*a%p; } return res; } int main() { primes(N); scanf("%d%d",&l,&r); int res=1; unordered_map<int,int> mp; for(int i=l;i<=r;i++) { if(!st[i]) { int j=i; for(int k=2;k*k<=j;k++) { if(j%k==0) { int t=0; while(j%k==0)t++,j/=k; mp[k]=max(mp[k],t); } } if(j>1)mp[j]=max(mp[j],1); } } for(auto [x,y]:mp)res=1ll*res*ksm(x,y,mod)%mod; printf("%d",res==1?-1:res); return 0; }

__EOF__

本文作者acwing_zyy
本文链接https://www.cnblogs.com/zyyun/p/15873258.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   zyy2001  阅读(105)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示