比赛链接:https://ac.nowcoder.com/acm/contest/5773
A.第k小数
题意
求第k小数
题解
这道题有点毒,sort会被卡掉,其实只要把前k个小的数排出来就行了,所以用nth_element(a,a+k-1,a+n);意思就是只把第k个小的数放在k的位置,第 k个元素之前的元素都小于它,但不必是有序的。同样,第 k个元素后的元素都大于它,但也不必是有序的。
代码
#include<bits/stdc++.h> using namespace std; #define fi first #define se second #define pb push_back #define mp make_pair #define lowbit(x) x&(-x) typedef long long ll; typedef pair<int,int> pii; typedef pair<ll, ll> pll; const int N = 5e6+5; const ll mod = 1e9+7; const int INF = 0x3f3f3f3f; const double eps =1e-9; const double PI=acos(-1.0); const int dir[4][2]={-1,0,1,0,0,-1,0,1}; const int exdir[4][2]={1,1,1,-1,-1,1,-1,-1}; ll qpow(ll x,ll y){ ll ans=1,t=x; while(y>0){ if(y&1)ans*=t,ans%=mod; t*=t,t%=mod; y>>=1; } return ans%mod; } int a[N]; void solve(){ int n,k;cin>>n>>k; for(int i=0;i<n;i++)cin>>a[i]; nth_element(a,a+k-1,a+n); cout<<a[k-1]; } int main(){ ios::sync_with_stdio(0); cin.tie(0);cout.tie(0); int t;cin>>t; while(t--)solve(),cout<<'\n'; //solve(); return 0; }
B不平行的直线
题意
给一些不重合的点,可以两两成直线,问最多选多少两两相交的直线
题解
找斜率不同的直线个数即可,注意垂直x轴情况
代码
#include<bits/stdc++.h> using namespace std; #define fi first #define se second #define pb push_back #define mp make_pair #define lowbit(x) x&(-x) typedef long long ll; typedef pair<int,int> pii; typedef pair<ll, ll> pll; const int N = 1e5+5; const ll mod = 1e9+7; const int INF = 0x3f3f3f3f; const double eps =1e-9; const double PI=acos(-1.0); const int dir[4][2]={-1,0,1,0,0,-1,0,1}; const int exdir[4][2]={1,1,1,-1,-1,1,-1,-1}; ll qpow(ll x,ll y){ ll ans=1,t=x; while(y>0){ if(y&1)ans*=t,ans%=mod; t*=t,t%=mod; y>>=1; } return ans%mod; } int x[201],y[201]; void solve(){ int n;cin>>n; set<double>s; for(int i=0;i<n;i++)cin>>x[i]>>y[i]; int f=0; for(int i=0;i<n;i++){ for(int j=i+1;j<n;j++){ if(x[i]==x[j])f=1; else{ s.insert(1.0*(y[i]-y[j])/(x[i]-x[j])); } } } cout<<s.size()+f; } int main(){ ios::sync_with_stdio(0); cin.tie(0);cout.tie(0); //int t;cin>>t; //while(t--)solve(),cout<<'\n'; solve(); return 0; }
C.丢手绢
题意
给你一些点,围成一个圈,每两相邻个点有距离,求两个点之间的最大距离,距离定义为圆的弧长
题解
选一个参考点,求所有点到这点的距离,通过相差就可以求出任意两点的距离,然后枚举每一个点,求这点到其他点最大距离,我们发现这是一个凸函数,直接三分即可
代码
#include<bits/stdc++.h> using namespace std; #define fi first #define se second #define pb push_back #define mp make_pair #define lowbit(x) x&(-x) typedef long long ll; typedef pair<int,int> pii; typedef pair<ll, ll> pll; const int N = 1e5+5; const ll mod = 1e9+7; const int INF = 0x3f3f3f3f; const double eps =1e-9; const double PI=acos(-1.0); const int dir[4][2]={-1,0,1,0,0,-1,0,1}; const int exdir[4][2]={1,1,1,-1,-1,1,-1,-1}; ll qpow(ll x,ll y){ ll ans=1,t=x; while(y>0){ if(y&1)ans*=t,ans%=mod; t*=t,t%=mod; y>>=1; } return ans%mod; } int sum[N],a[N]; int judge(int x,int y){ if(x==y)return 0; //cout<<x<<' '<<y<<' '<<min(abs(sum[x]-sum[y]),a[1]-abs(sum[x]-sum[y]))<<endl; return min(abs(sum[x]-sum[y]),a[1]-abs(sum[x]-sum[y])); } void solve(){ int n;cin>>n; for(int i=2;i<=n;i++)cin>>a[i],sum[i]+=sum[i-1]+a[i]; cin>>a[1];a[1]+=sum[n]; int ans=0; for(int i=1;i<=n;i++){ int l=0,r=n+1; while(l+1<r){ int lm=(l+r)>>1,rm=(lm+r)>>1; if(judge(lm,i)>judge(rm,i))r=rm; else l=lm; } ans=max(ans,judge(l,i)); } cout<<ans<<endl; } int main(){ ios::sync_with_stdio(0); cin.tie(0);cout.tie(0); //int t;cin>>t; //while(t--)solve(),cout<<'\n'; solve(); return 0; }
D.二分
题意
不好描述
题解
差分裸题,三种情况讨论
if(s=="+")m[x]--,now++;//负无穷到x-1,全部加一 if(s=="-")m[x+1]++;//x+1到正无穷全部加一 if(s==".")m[x]++,m[x+1]--;//x加一
统计时算一下前缀和就好了
可以离散化一下,亦可以直接map记录
代码
#include<bits/stdc++.h> using namespace std; #define fi first #define se second #define pb push_back #define mp make_pair #define lowbit(x) x&(-x) typedef long long ll; typedef pair<int,int> pii; typedef pair<ll, ll> pll; const int N = 1e5+5; const ll mod = 1e9+7; const int INF = 0x3f3f3f3f; const double eps =1e-9; const double PI=acos(-1.0); const int dir[4][2]={-1,0,1,0,0,-1,0,1}; const int exdir[4][2]={1,1,1,-1,-1,1,-1,-1}; ll qpow(ll x,ll y){ ll ans=1,t=x; while(y>0){ if(y&1)ans*=t,ans%=mod; t*=t,t%=mod; y>>=1; } return ans%mod; } void solve(){ map<int,int>m; int n;cin>>n; int now=0; for(int i=0;i<n;i++){ int x;string s;cin>>x>>s; if(s=="+")m[x]--,now++; if(s=="-")m[x+1]++; if(s==".")m[x]++,m[x+1]--; } int ans=0; for(auto i:m){ now+=i.se; ans=max(ans,now); } cout<<ans; } int main(){ ios::sync_with_stdio(0); cin.tie(0);cout.tie(0); //int t;cin>>t; //while(t--)solve(),cout<<'\n'; solve(); return 0; }
E.交换
题意
给你一个个数列,问最少交换几次才能使其从大到小有序
题解
第一反应可能是逆序对,或者最长上升子序列之类的,但是这个要求可以任意换,可以不相邻,比如说312,可以3-2,2-1,其实在2-1时成了一个环,每出现一个环答案就会减一,所以找环的个数
代码
#include<bits/stdc++.h> using namespace std; #define fi first #define se second #define pb push_back #define mp make_pair #define lowbit(x) x&(-x) typedef long long ll; typedef pair<int,int> pii; typedef pair<ll, ll> pll; const int N = 1e5+5; const ll mod = 1e9+7; const int INF = 0x3f3f3f3f; const double eps =1e-9; const double PI=acos(-1.0); const int dir[4][2]={-1,0,1,0,0,-1,0,1}; const int exdir[4][2]={1,1,1,-1,-1,1,-1,-1}; ll qpow(ll x,ll y){ ll ans=1,t=x; while(y>0){ if(y&1)ans*=t,ans%=mod; t*=t,t%=mod; y>>=1; } return ans%mod; } int a[N],b[N],v[N]; void solve(){ int n;cin>>n; for(int i=1;i<=n;i++)cin>>a[i],b[i]=a[i]; sort(a+1,a+1+n); int now=0; for(int i=1;i<=n;i++){ if(!v[i]){ int k=lower_bound(a+1,a+1+n,b[i])-a; v[i]=1; while(!v[k]){ v[k]=1; k=lower_bound(a+1,a+1+n,b[k])-a; } now++; } } cout<<n-now; } int main(){ ios::sync_with_stdio(0); cin.tie(0);cout.tie(0); //int t;cin>>t; //while(t--)solve(),cout<<'\n'; solve(); return 0; }