#补题2 2020年牛客算法入门课练习赛1

A:第k小数
考查一个函数nth_element()
具体用法:传送门
其实就是只排好了数组中指定的一个数的位置,时间复杂度低
(因为这个题,去看了一下有关排序的其他函数,传送门)
附AC代码:

#include
#include
using namespace std;
const int N=2e7+10;
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;
}
int  main()
{
    int a[N];
    int t;
    t=read();
    int n,m;
    while(t--)
    {
        n=read();
        m=read();
        for(int i=0;i<n;i++)
        {
            a[i]=read();
        }
        nth_element(a,a+m-1,a+n); //第m小的数,前面有m-1个数,第二个参数就是首地址+(m-1)
        cout<<a[m-1]<<endl;
    }

}

B:不平行的直线
题目要求直线两两不平行也不重合,我们知道斜率k相同的话,必定是平行或重合的,那么把一个点和其他所有点连成的直线的斜率判断一遍即可
附AC代码:

#include
#include
using namespace std;
const int N=210;
int x[N],y[N];
map<double,bool> f;
int main()
{
    int t,cnt=0;
    cin>>t;
    for(int i=0;i<t;i++)
    {
        cin>>x[i]>>y[i];
    }
    for(int i=0;i<t;i++)
    {
        for(int j=i+1;j<t;j++)
        {
            double ly=y[j]-y[i];
            double lx=x[j]-x[i];
            double k;
            if(lx==0) k=12.15;//需要一个测试样例里没有的斜率orz...
            else k=ly/lx;
            if(!f[k])
            {
                f[k]=true;
                cnt++;
            }
        }
    }
    cout<<cnt<<endl;
}

C:丢手绢
输入样例的最后一行感觉是多余的…
围成一个圈,两个人的距离一定不会超过圈的一半tmp,如果没有超过,那么当前数据就加上到下个人的距离,如果超过了,那么此时两个人的距离就是min(maxx, sum - maxx),尺取法遍历所有情况

#include 
using namespace std;
const int maxn = 1e5 + 7;
typedef long long ll;
int n, a[maxn];
ll sum;
int main()
{
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) scanf("%d", &a[i]), sum += a[i];
    int tp = 1;
    ll tmp = sum / 2, maxx = 0, ans = 0; //maxx记录两个人的距离
    for (int i = 1; i <= n; i++) {
        while (maxx < tmp) {
            maxx += a[tp++];
            if(tp == n + 1) tp = 1; //环
        }
        ans = max(ans, min(maxx, sum - maxx)); //因为"/"是整除,所有sum-maxx不是都比maxx小的
        maxx -= a[i];
    }
    printf("%lld\n", ans);
}


D:二分(二分的标题,差分的本质)

mp记录每一个数被猜测到的可能性
以输入样例“6 +”为例,说明猜测的数比6大,我们将7~∞的每一个数的可能性都+1
同理“8 -”,我们将-∞~7的每一个的可能性都+1
“5 .”只将数字5的可能性+1

#include
#include
#include
using namespace std;
const int INF=0x7f7f7f7f;  //0x7f7f7f7f即int类型的最大值(加一个数就会溢出的那种大)
map<int,int>mp;
int main()
{
    int t,n;
    char ch;
    cin>>t;
    while(t--)
    {
        cin>>n>>ch;
        if(ch=='.')
        {
            mp[n]++;
            mp[n+1]--;
        }
        if(ch=='+')
        {
            mp[-INF]++;
            mp[n]--;
        }
        if(ch=='-')
        {
            mp[n+1]++;
            mp[INF]--;
        }
    }
    int ans=-INF;
    int k=0;
    for(auto x:mp)
    {
      k+=x.second; //求和,k即为每一个数的可能性,差分逆运算求原数
      ans=max(ans,k); //最大的就是答案了
    }
    cout<<ans<<endl;
}

E:交换
这题不能用选择排序,会超时。
可以用另一个数组复刻原数组的值,记住数组下标,然后逐个比较,不一样就交换。交换后重新更新下标。
附AC代码:

#include
using namespace std;
const int maxn = 1e5+5;
typedef long long ll;
int a[maxn],b[maxn];
map<int,int>pos;
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=0; i<n; i++)
    {
        scanf("%d",&a[i]);
        b[i]=a[i];
        pos[a[i]]=i;
    }
    sort(b,b+n);
    int ans=0;
    for(int i=0; i<n; i++)
    {
        if(a[i]==b[i])
            continue;
        int p=pos[b[i]];
        swap(a[i],a[p]);
        pos[a[i]]=i;
        pos[a[p]]=p;
        ans++;
    }
    printf("%d\n",ans);
}

你可能感兴趣的:(#补题2 2020年牛客算法入门课练习赛1)