1、最少刷题数
小蓝老师教的编程课有 N 名学生,编号依次是 1...N。
第 i 号学生这学期刷题的数量是Ai。
对于每一名学生,请你计算他至少还要再刷多少道题,才能使得全班刷题比他多的学生数不超过刷题比他少的学生数。
第一行包含一个正整数 N。
第二行包含 N 个整数:A1,A2,A3,...,AN。
输出 N 个整数,依次表示第 1...N号学生分别至少还要再刷多少道题。
对于 30%的数据,1≤N≤1000,0≤Ai≤1000。
对于 100% 的数据,1≤N≤100000,0≤Ai≤100000。
- 5
- 12 10 15 20 6
0 3 0 0 7
因为数据会有相等的,所以使用二分。
- #include<bits/stdc++.h>
- using namespace std;
- #define int long long
- #define fp(i,a,b) for(int i=a;i<=b;++i)
- const int N=1e6+10;
- const int mod=1e9+7;
- const double eps=1e-5;
- typedef double db;
- int n;
- int mmax;
- int a[N],b[N];
- bool check(int x,int y)
- {
- int st=-1;
- int ed=-1;
-
- int l=1,r=n;
-
- while(l<r)
- {
- int mid=(l+r)>>1;
- if(b[mid]>=x)r=mid;
- else l=mid+1;
- }
- st=l;
-
- l=1,r=n;
- while(l<r)
- {
- int mid=(l+r+1)>>1;
- if(b[mid]<=x)l=mid;
- else r=mid-1;
- }
-
- ed=l;
-
- int lcnt=st-1;
- int rcnt=n-ed;
- if(y<x)lcnt--;
- if(rcnt<=lcnt)return true;
- else return false;
-
- }
- signed main()
- {
- cin>>n;
-
- fp(i,1,n)cin>>a[i],b[i]=a[i],mmax=max(mmax,a[i]);
-
- sort(b+1,b+1+n);
-
- for(int i=1;i<=n;i++)
- {
- int l=a[i],r=mmax;
- while(l<r)
- {
- int mid=(l+r)>>1;
- if(check(mid,a[i]))r=mid;
- else l=mid+1;
- }
- cout<<l-a[i]<<" ";
- }
-
-
- return 0;
- }
-
-
2、最大公约数
给定一个数组,每次操作可以选择数组中任意两个相邻的元素 x, y并将其中的一个元素替换为gcd(x,y),其中 gcd(x,y) 表示 x 和 y 的最大公约数。请问最少需要多少次操作才能让整个数组只含 1。
输入的第一行包含一个整数 n,表示数组长度。
第二行包含 n 个整数 a1,a2,…,an,相邻两个整数之间用一个空格分隔。
输出一行包含一个整数,表示最少操作次数。如果无论怎么操作都无法满足要求,输出 −1。
输入 #1
3 4 6 9
输出 #1
4
【评测用例规模与约定】
蓝桥杯 2022 国赛 A 组 D 题。
首先要使整个数列为 1,必须要先有一个位置的值为 1,再逐步拓展。问题就转化为拼出一个 1 的最少步数。又由于题目要求只能用相邻两数来进行gcd,所以要拼出 1 个 1 必须是一个区间内的数进行 gcd。维护一个区间 gcd,套个双指针就可以了。这里用的是 st 表,时间复杂度O(nlogn+n)。
- #include<bits/stdc++.h>
- using namespace std;
- #define int long long
- #define fp(i,a,b) for(int i=a;i<=b;++i)
- const int N=1e5+10;
- const int mod=1e9+7;
- const double eps=1e-5;
- typedef double db;
- int Max[N][25];
- int lg[N];
- int n;
- int a[N];
- int gcd(int a, int b)
- {
- return b ? gcd(b, a % b) : a;
- }
- int query(int l,int r)
- {
- int k=lg[r-l+1];
- return gcd(Max[l][k],Max[r-(1<<k)+1][k]);
- }
- signed main()
- {
- cin>>n;
-
- int cnt=0;
-
- fp(i,1,n)
- {
- cin>>Max[i][0];
- a[i]=Max[i][0];
- if(a[i]==1)cnt++;
- }
-
- for (int i = 2; i <= n; i++) lg[i] = lg[i >> 1] + 1;
- for(int j=1;j<=lg[n];j++)
- {
- for(int i=1;i+(1<<j)-1<=n;i++)
- {
- Max[i][j]=gcd(Max[i][j-1],Max[i+(1<<(j-1))][j-1]);
- }
- }
-
- if(cnt)
- {
- cout<<n-cnt;
- return 0;
- }
- if(query(1,n)>1)
- {
- cout<<-1;
- return 0;
- }
-
-
- int ans=n;
-
- for (int l=1,r=1;r<=n;r++) {
- while (l<r && query(l+1,r)==1) l++;
- if (query(l,r)==1) ans=min(ans,r-l);
- }
- cout<<n+ans-1;
-
-
- return 0;
- }
-
-