这次比赛真的。。。槽点满满啊。。。A,C,D,E都有问题。。。(害我罚时高到飞起)

A.第k小数

读完题,我:这nlogn直接艹,问题不大!

然后。。。

段错误*n

我:???

然后,天真的以为sort出锅了,码了个基排。。。

然后。。。

段错误*n

我:???

之后,自暴自弃,数组开个1e7,于是。。。

答案正确。

我:???

emmm,这题,没啥技巧,sort被卡了,直接上无脑基排吧。。。

注意分正数和负数两个情况讨论

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=1e7+1;
int a[N],d[N],n,k;
const int base=256,mod=255;
int b[N],c[4][N];
inline int read(){
    int x = 0, f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9'){
        if (ch == '-')
            f = -1;
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9'){
        x = (x<<1) + (x<<3) + (ch^48);
        ch = getchar();
    }
    return x * f;
}
inline void base_sort(){
    memset(c,0,sizeof(c));
    for(int i=1;i<=n;++i){
        c[0][a[i]&mod]++;
        c[1][(a[i]>>8)&mod]++;
        c[2][(a[i]>>16)&mod]++;
        c[3][(a[i]>>24)]++;
    }
    for(int i=1;i<=mod;++i){
        c[0][i]+=c[0][i-1];
        c[1][i]+=c[1][i-1];
        c[2][i]+=c[2][i-1];
        c[3][i]+=c[3][i-1];
    }
    for(int i=n;i;--i){
        b[c[0][a[i]&mod]--]=a[i];
    }
    for(int i=n;i;--i){
        a[c[1][(b[i]>>8)&mod]--]=b[i];
    }
    for(int i=n;i;--i){
        b[c[2][(a[i]>>16)&mod]--]=a[i];
    }
    for(int i=n;i;--i){
        a[c[3][(b[i]>>24)]--]=b[i];
    }
}
int main(){
    int T=read();
    while(T--){
        n=read(),k=read();int e=0,p=0;
        for(int i=1;i<=n;++i){
            int x=read();
            if(x<0){
                d[++e]=x;
            }else{
                a[++p]=x;
            }
        }
        int reflag=1;
        if(e>=k){
            n=e;reflag=-1;
            for(int i=1;i<=n;++i){
                a[i]=-d[i];
            }
        }else{
            n=p;
        }
        base_sort();
        printf("%d\n",a[k]*reflag);
    }
    return 0;
}

B.不平行的直线

比较斜率是否一样即可(注意讨论没有斜率的情况)

因为double可能出精度,直接可能炸,于是。。。将分子和分母用pair存起来,然后直接上set就行了。

(为了正确比较,记得化成最简分数,且由于可能为负,我们规定分子必须为非负,就行了)

复杂度:

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=201;
int x[N],y[N];
set<pair<int,int> >sp;
int main(){
    int n;
    scanf("%d",&n);
    int ans=0;
    for(int i=1;i<=n;++i){
        scanf("%d%d",&x[i],&y[i]);
    }
    bool flag=0;
    for(int i=1;i<=n;++i){
        for(int j=i+1;j<=n;++j){
            if(x[i]==x[j]){
                flag=1;
                continue;
            }
            int X=y[i]-y[j],Y=x[i]-x[j];
            if(X<0)X=-X,Y=-Y;
            int D=__gcd(X,Y);
            X/=D,Y/=D;
            sp.insert(make_pair(X,Y));
        }
    }
    int res=sp.size()+flag;
    printf("%d",res);
    return 0;
}

C.丢手绢

我们枚举每一个点,然后算出离这个点最远的点离这个点的距离就行了。

如果暴力,明显不可行。

观察到可以直接二分/三分。直接上模板即可

复杂度:

代码:

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e5+1;
int s[N],pos[N],n;
inline int calc(int x,int y){
    if(x>y){
        swap(x,y);
    }
    return min(abs(pos[x]-pos[y]),pos[x]+s[n]+pos[n]-pos[y]);
}
signed main(){
    scanf("%lld",&n);
    for(int i=1;i<=n;++i){
        scanf("%lld",&s[i]);
    }
    scanf("%lld",&s[n]);//这句话看情况加不加吧/xk题面问题
    for(int i=2;i<=n;++i){
        pos[i]=pos[i-1]+s[i-1];
    }
    int ans=0;
    for(int i=1;i<=n;++i){
        int l=1,r=n,res=0;
        while(l<=r){
            int lc=l+(r-l)/3,rc=r-(r-l)/3;
            int L=calc(i,lc),R=calc(i,rc);
            if(L>R){
                res=L,r=rc-1;
            }else{
                res=R,l=lc+1;
            }
        }
        ans=max(ans,res);
    }
    printf("%lld",ans);
    return 0;
}

D.二分

这题也是诡异。。。

输入描述有这句:

接下来n行,首先是猜的数,然后是一个空格,然后是一个符号。符号如果是“+”说明猜的数比答案大,“-”说明比答案小,“.”说明猜到了答案。

然后,样例解释是:

当目标数组是5时,5 . 5 . 8 - 这三个回答都是正确的

两者明显矛盾了。。。/xk

通过我的多次提交牺牲(qwq),我们发现,输入描述的是正确的,我们按输入描述的做就行了。。。

我们首先,对于每个回答,算出它的可行解的范围。

那么,很明显的,答案就是在最多的可行解范围内的点所包含的可行解范围。(有点绕/xk)

但是,每个可行解的范围其实很大的,我们不可能直接统计,怎么办?

注意到,非端点的数字其实没什么用处(也就是说我们把所有的端点都算一遍就可以求出答案了)

那么,我们直接将所有可行解离散化一遍,然后就是简单的区间加,单点查询问题了,套个数据结构就可以了(ps:建议数组开大点,玄学。。。)

复杂度:

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+1;
#define int long long
struct node{
    int l,r;
}t[N];
int b[N],s[N],m,e,inf;
inline int lowbit(int x){
    return x&-x;
}
inline void insert(int x,int y){
    while(x<=e){
        s[x]+=y;x+=lowbit(x);
    }
}
inline int find(int x){
    int ans=0;
    while(x){
        ans+=s[x];x-=lowbit(x);
    }
    return ans;
}
signed main(){
    int n;
    scanf("%lld",&n);
    e=0,inf=1e17;
    for(int i=1;i<=n;++i){
        int x;char y;
        cin>>x>>y;
        if(y=='.'){//x-x ans+1
            t[i]=(node){x,x};
        }else if(y=='-'){
            t[i]=(node){x+1,inf};
        }else{
            t[i]=(node){-inf,x-1};
        }
        b[++e]=t[i].l,b[++e]=t[i].r;
    }
    sort(b+1,b+e+1);
    m=unique(b+1,b+e+1)-b-1;
    for(int i=1;i<=n;++i){
        t[i].l=lower_bound(b+1,b+m+1,t[i].l)-b;
        t[i].r=lower_bound(b+1,b+m+1,t[i].r)-b;
        insert(t[i].l,1),insert(t[i].r+1,-1);
    }
    int ans=0;
    for(int i=1;i<=m;++i){
        ans=max(ans,find(i));
    }
    printf("%d",ans);
    return 0;
}

E.交换

一开始以为是交换相邻的,然后光荣贡献了罚时

这道题,直接上结论就行了。

我们把一个点和它排完序后的位置连一条单向边,那么答案就是点的个数-环的个数/每个环的大小-1的和

直接跑暴力一遍就行了,因为每个点都只会被访问一次,所以复杂度是

(看我开的数组就可以猜到我经历了什么qwq)

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=1000001;
int a[N],b[N],nex[N];
bool vis[N];
int main(){
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;++i){
        scanf("%d",&a[i]);b[i]=a[i];
    }
    sort(b+1,b+n+1);
    int ans=0;
    for(int i=1;i<=n;++i){
        int x=lower_bound(b+1,b+n+1,a[i])-b;
        nex[i]=x;
    }
    for(int i=1;i<=n;++i){
        if(nex[i]==i||vis[i])continue;
        int tot=0,now=i;
        while(!vis[now]){
            ++tot,vis[now]=1;now=nex[now];
        }
        ans+=(tot-1);
    }
    printf("%d",ans);
    return 0;
}