2020牛客寒假算法基础集训营6
题意:
现在有正整数集合 A 和 B,每个集合里有 N 个数,你要建立他们间的一一映射
将每对配对的数字相加可以得到 N 个和,你要做的就是最大化第 K 大的和
1≤K≤N≤100,000 输入的所有数字不超过 108
思路:
我们要使得第K大的和尽可能大,显然可以贪心:首先,组成这K对数字的显然是A中最大的K个数字和B中最大的K个数字。
问题转化为怎样配对使得最小的和最大:我们发现,如果A1<A2,B1<B2,那么一定是由A1和B2配对较优。
经过简单的归纳可以得到,倒序配对是最优的,这样就解决了问题。
#include<bits/stdc++.h> using namespace std; const int N =1e5+10; int a[N],b[N],sum[N]; int n,k; int main(){ cin>> n >> k; for(int i=1;i<=n;i++) cin>> a[i]; for(int i=1;i<=n;i++) cin>> b[i]; sort(a+1,a+1+n,greater<int>()); sort(b+1,b+1+n,greater<int>()); int ans =2e8+17; for(int i=1;i<=k;i++) ans =min(ans,a[i]+b[k+1 - i]); cout<<ans<<endl; return 0; }
B.图
题意:
现在有一个N个点的有向图,每个点仅有一条出边
你需要求出图中最长的简单路径包含点的数量。
思路:
由题意可知,这是一个基环树。关于这类题。我们可以先找出环,把环的相关点标记上环的长度。
那么简单路径就是除环外的点到环的距离加上环的长度。
#include<bits/stdc++.h> using namespace std; const int N =1e6+17; int vis[N],to[N],h[N]; int n,ans; void dfs(int id){ if(h[to[id]] == 0){ int res = 1; int k =to[id]; while(k != id){ res++; k = to[k]; } h[k] = res; vis[k] = 1; k = to[k]; while(k != id){ h[k] =res; vis[k] =1; k =to[k]; } return ; } h[id] =0; if(vis[to[id]] == 0){ dfs(to[id]); if(vis[id] == 0){ h[id] = h[to[id]]+1; vis[id] =1; } } else if(vis[to[id]] ==1) { h[id] = h[to[id]]+1; vis[id] =1; return ; } } int main(){ cin>>n; for(int i=1;i<=n;i++)cin>>to[i]; for(int i=1;i<=n;i++) h[i] =-1; for(int i=1;i<=n;i++){ if(vis[i] == 0) dfs(i); ans =max(ans,h[i]); } cout<<ans<<endl; return 0; }
D.重排列
题意:
一个序列的重排列是指对这个序列中的元素进行若干次(包括0次)交换操作后得到的新序列.
在本题中,序列中可能出现重复的数字,他们被视作不同的元素.
现在有两个长度为 N 的非负整数序列 A 和 B,问有多少种 A 的重排列满足对于所有的 1≤i≤N,有Ai≤Bi
由于答案可能很大,你只需要输出答案对1e9+7取模的结果.
思路:
将a,b排序,双指针模拟一下。
#include<bits/stdc++.h> using namespace std; const int N = 1e5+17; const int mod = 1e9+7; int a[N],b[N],n; int main(){ cin>>n; for(int i=1;i<=n;i++)cin>>a[i]; for(int i=1;i<=n;i++)cin>>b[i]; sort(a+1,a+1+n); sort(b+1,b+1+n); long long ans =1; for(int i=1,j=0;i<=n;i++){ while(j<n&& a[j+1] <=b[i]) j++; ans = ans * max(0LL,(j-i+1LL)*1LL)%mod; } ans =(ans+mod)%mod; cout<<ans<<endl; return 0; }
E.立方数
题意:对于给定的正整数 N,求最大的正整数 A,使得存在正整数 B,满足 A3B=N;
思路:先对N质因数分解。用N去对质因数试除,最后用二分法来验证余下的X是不是一个完全立方数。
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 4e4+5; int vis[maxn],p[maxn],tot; ll n,cnt,ans,l,r,mid; int main() { for(int i=2;i<maxn;i++) { if(!vis[i]) { p[tot++]=i; for(int j=i*2;j<maxn;j+=i) vis[j]=1; } } int t;cin>>t; while(t--) { cin>>n; ans=1; for(int i=0;i<tot;i++) { if(n%p[i])continue; cnt=0; while(n%p[i]==0) { n/=p[i]; cnt++; if(cnt==3) { ans*=p[i]; cnt=0; } } } l=1;r=1e6; while(l<=r) { mid=(l+r)/2; if(mid*mid*mid==n) { ans*=mid; break; } else if(mid*mid*mid<n) l=mid+1; else r=mid-1; } cout<<ans<<endl; } return 0; }
F.十字阵列
题意:
小 Q 新学会了一种魔法,可以对一个 N行M列 的网格上的敌人造成伤害
第 i 次使用魔法可以对网格上的一个十字形区域(即第 xi 行和第 yi 列的并)中的每个格子上的敌人造成 zi 点伤害
现在小 Q 一共使用了 H 次魔法,你需要在所有的施法完成之后统计造成伤害的情况,详见输出描述
思路:
设3个数组a[],b[]和ab[][],分别统计对行,列和每格造成的伤害
进行操作(xi,yi,zi)时,a[xi],b[yi],ab[xi][yi]都加上zi
每次询问一格的答案时,只要查询a[x]+b[y]-ab[x][y]就好了
#include<bits/stdc++.h> using namespace std; const int N= 2010; const int mod = 1e9+7; int x[N],y[N],xy[N][N],n,m,h; int main(){ cin>>n>>m>>h; long long ans =0; while(h--){ int i,j,v; cin>>i>>j>>v; x[i]+=v,y[j]+=v,xy[i][j]+=v; } for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) ans = (ans + (long long)(x[i] + y[j] - xy[i][j]) * (i + j) % mod) % mod; cout<<(ans+mod)%mod<<endl; return 0; }
G.括号序列
题意:
合法括号序列的定义是:
1.空序列是合法括号序列
2.如果 S 是一个合法括号序列,那么(S)是合法括号序列
3.如果 A 和 B 都是合法括号序列,那么 AB 是一个合法括号序列
现在给定一个括号序列,求最少删去几个括号能得到一个合法的括号序列
#include<bits/stdc++.h> using namespace std; const int N = 1e6+10; char s[N]; int main(){ int t;cin>>t; while(t--){ int n;cin>>n; scanf("%s",s+1); stack<int> st; for(int i=1;i<=n;i++){ if(!st.empty()){ char t = s[st.top()]; if( t == '(' && s[i] == ')') st.pop(); else st.push(i); } else st.push(i); } cout<<st.size()<<endl; } return 0; }
J.签到题
题意:
现有一个边长为正整数的三角形,问能否以其三个顶点为圆心画三个圆,使三个圆两两外切
三边长均不超过108。
思路:
三角形三边长a,b,c,三个顶点的圆半径为x,y,z.则 x+y =a,x+z =b; y+z =c .解出x,y,z.
作者:珩月 链接:https://ac.nowcoder.com/discuss/367149?type=101&order=0&pos=1&page=2 来源:牛客网 #include<bits/stdc++.h> using namespace std; double a[3], b[3]; int main() { cin >> a[0] >> a[1] >> a[2]; sort(a, a + 3); if(a[0] + a[1] <= a[2]){ puts("wtnl"); return 0; } puts("Yes"); b[1] = (a[2] - a[1] + a[0]) / 2; b[0] = a[0] - b[1], b[2] = a[2] - b[1]; printf("%.2lf %.2lf %.2lf", b[0], b[1], b[2]); return 0; }

浙公网安备 33010602011771号