A题:
题意:和题目一样,就是求第k小数。
思路:暴力肯定就sort了,不过数据太大,sort也过不了,那么根据快排,我们可以一次性砍掉一半左右的数据,只需要关心第k小数所在的数据范围就好了。后来才知道还有一个nth_element这个神奇的东西,会把第k个数直接放在k的位置。用法:nth_element(first,nth,last);我发现用这个的时候是把数据存放在a[0]-a[n-1]m排序输出k小数的时候输出的是a[k],也就是经过这个函数之后,数据k是放在a[k]位置,而不是a[k-1].下面是我的ac代码和用了element的代码。
1:
#include<iostream> #include<cstdio> #include<cstring> #include<string> #include<cmath> #include<map> #include<algorithm> using namespace std; typedef long long LL; const int maxn=5e6+5; const LL mod=1e9+7; inline int read() { char ch=getchar();int x=0,f=1; while(ch<'0' || ch>'9') {if(ch=='-')f=-1;ch=getchar();} while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } int a[maxn]; int c[maxn]; int find(int r,int k) { if(r==1) { return a[r]; } int low=1,high=r; int num=a[1]; for(int i=2;i<=r;++i) { if(a[i]<=num) { c[low++]=a[i]; } else { c[high--]=a[i]; } } if(low==k) return num; else if(low<k) { for(int i=low+1;i<=r;++i) { a[i-low]=c[i]; } return find(r-low,k-low); } else { for(int i=1;i<low;++i) { a[i]=c[i]; } return find(low-1,k); } } void solve() { int n,k; n=read(); k=read(); for(int i=1;i<=n;++i) { a[i]=read(); } cout<<find(n,k)<<"\n"; } int main() { // cout<<"Accepted!\n"; int t; cin>>t; while(t--) { solve(); } return 0; }
2:
#include<iostream> #include<cstdio> #include<cstring> #include<string> #include<cmath> #include<map> #include<algorithm> using namespace std; typedef long long LL; const int maxn=5e6+100; const LL mod=1e9+7; int read() { char ch=getchar();int x=0,f=1; while(ch<'0' || ch>'9') {if(ch=='-')f=-1;ch=getchar();} while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } int a[maxn]; int main() { // cout<<"Accepted!\n"; int t; cin>>t; while(t--) { int n,k; n=read(); k=read(); for(int i=0;i<n;++i) { a[i]=read(); } // cout<<k<<"\n"; nth_element(a,a+k,a+n); cout<<a[k]<<"\n"; } return 0; }
B题:
题意:给n个点,问最多选出多少条直线不能平行也不重合。
思路:我刚开始以为一个点用过就不能用了,后来才知道可以重复使用。既然这样那就直接暴力检查任意两条直线就好了,那样就O( ),我们稍微优化一下,运用set的性质,我们把一条直线的斜率放进去就很好的去除了重合和平行,那么还有一个精度问题,我们就不直接使用斜率,而是用分母分子这样一组数来表示,同时我们规定分母一定为正。
#include<iostream> #include<cstdio> #include<cstring> #include<string> #include<cmath> #include<map> #include<set> #include<algorithm> using namespace std; typedef long long LL; const int maxn=1e5+5; const LL mod=1e9+7; int read() { char ch=getchar();int x=0,f=1; while(ch<'0' || ch>'9') {if(ch=='-')f=-1;ch=getchar();} while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } int gcd_(int a,int b) {return b==0?a:gcd_(b,a%b);} LL fpow(LL a,LL b) { LL res=1; while(b) { if(b&1) res=(res*a)%mod; a=(a*a)%mod; b>>=1; } return res; } int a[205],b[205]; set<pair<int,int> > se; int main() { // cout<<"Accepted!\n" int n; cin>>n; for(int i=1;i<=n;++i) { cin>>a[i]>>b[i]; } int flag=0; for(int i=1;i<n;++i) { for(int j=i+1;j<=n;++j) { if(b[i]==b[j] ) { flag=1; continue; } int X=a[i]-a[j],Y=b[i]-b[j]; if(X<0) X=-X,Y=-Y; int Z=gcd_(X,Y); X/=Z; Y/=Z; se.insert(make_pair(X,Y)); } } cout<<se.size()+flag; return 0; }
C题:
题意:这个没啥可说的。
思路:不过给的样例数据多了3,,,。直接三分就好了。
#include<iostream> #include<cstdio> #include<cstring> #include<string> #include<cmath> #include<map> #include<algorithm> using namespace std; typedef long long LL; const int maxn=1e5+5; int a[maxn]; int s[maxn]; int dis(int x,int y) { if(x==y) return 0; return min(abs(s[x]-s[y]),a[1]-abs(s[x]-s[y])); } int main() { // cout<<"Accepted!\n"; int n; cin>>n; for(int i=2;i<=n;++i) { cin>>a[i]; s[i]=s[i-1]+a[i]; } cin>>a[1]; a[1]+=s[n]; int ans=0; for(int i=1;i<=n;++i) { int l=1,r=n; while(l+1<r) { int m1=(l+r)>>1,m2=(m1+r)>>1; if(dis(m1,i)>dis(m2,i)) { r=m2; } else l=m1; } ans=max(ans,dis(l,i)); } cout<<ans; return 0; }
D题:
题意:给一组问的数据和回答,让你找一个数,使这些回答尽量多的正确。
思路:离散化加差分,最后前缀和找最大就好了。
#include<iostream> #include<cstdio> #include<cstring> #include<string> #include<cmath> #include<map> #include<set> #include<algorithm> using namespace std; typedef long long LL; const int maxn=1e5+5; set<int> se; map<int,int> mp; int main() { // cout<<"Accepted!\n"; int n; cin>>n; int x; char c; int res=0,s=0,inf=1e17; while(n--) { scanf("%d %c",&x,&c); if(c=='.') { se.insert(x); mp[x]++; se.insert(x+1); mp[x+1]--; } else if(c=='+') { se.insert(-inf); mp[-inf]++; se.insert(x); mp[x]--; } else { se.insert(x+1); mp[x+1]++; } } for(set<int>::iterator it=se.begin();it!=se.end();it++) { // cout<<*it<<' '<<mp[*it]<<"\n"; s+=mp[*it]; res=max(res,s); } cout<<res; return 0; }
E题:
题意任意交换两个孩子的位置,让他们从小到大排好序的交换次数。
思路:刚开始以为快排找交换次数,后来发现这是错的。然后我就想直接从第一个孩子开始排,直接把他放到所需的位置,就这样排一遍记录次数。写完提交发现这样是对的。后来通过群友巨巨们了解到,这就是找环的个数,仔细想想就是这样。一个环内所有的人要放到指定位置就是减缓环内元素-1次,那我们也不用记录环内元素个数,就直接记录环的个数,然后减去环的个数就好了。下面是我的ac代码。
#include<iostream> #include<algorithm> #include<map> using namespace std; const int maxn=1e5+5; int a[maxn]; int b[maxn]; map<int,int> mp; int main() { int n; cin>>n; for(int i=1;i<=n;++i) { cin>>a[i]; b[i]=a[i]; } sort(b+1,b+1+n); for(int i=1;i<=n;++i) { mp[b[i]]=i; } int res=0,pos=1; while(pos<n) { if(mp[a[pos]]!=pos) { int i=mp[a[pos]],temp=a[pos]; a[pos]=a[i]; a[i]=temp; res++; } else { pos++; } } cout<<res<<"\n"; }