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
说明/提示
【评测用例规模与约定】
- 对于 30% 的评测用例,n≤500,ai≤1000;
- 对于 50% 的评测用例,n≤5000,ai≤10^6;
- 对于所有评测用例,1≤n≤10^5,1≤ai≤10^9。
蓝桥杯 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;
}