百度之星第一场初赛部分题解

1001

贪心:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long LL;
#define MAXN 10005
int _,n,k;
LL num[MAXN],m;
bool solve()
{
    int u = upper_bound(num,num + n,m)- num;
    if(u == n)return true;
    else if(m < num[0])return false;
    if(num[u] > m)u--;
    m = num[u];
    while(u < n)
    {
        m += k;
        if(m < num[u + 1])return false;
        while(u != n && m >= num[u + 1])
            u++;
        if(u == n)return true;
        m = num[u];
        k--;
        if(u != n && k == 0)return false;
    }
    return true;
}
int main()
{
    for(int kcas = scanf("%d",&_);kcas <= _;kcas++)
    {
        printf("Case #%d:\n",kcas);
        scanf("%d%I64d%d",&n,&m,&k);
        for(int i = 0;i < n;i++)
            scanf("%I64d",&num[i]);
        sort(num,num + n);
        if(solve())puts("why am I so diao?");
        else puts("madan!");
    }
}

1002

暴力枚举,巧用STL:

#include<cstdio>
#include<set>
#include<algorithm>
#include<iostream>
using namespace std;
typedef long long LL;
const int MAXN = 10005;
set<LL>se;
set<LL> :: iterator it1,it2;
int n,m;
int ans[MAXN];
LL arr[MAXN];
int main()
{
    scanf("%d%d",&n,&m);
    for(int i = 0;i < n;i++)
        scanf("%I64d",&arr[i]);
    for(int j = 0;j < n;j++)
    {
        se.clear();
        for(int i = 0;i < 1000 && i + j < n;i++)
        {
            if(!se.count(arr[j + i]))
                se.insert(arr[j + i]);
            else
                break;
            int minn = *(se.begin());
            int maxn = *(se.rbegin());
            if(maxn - minn == se.size() - 1)
                ans[i]++;
        }
    }
    printf("Case #1:\n");
    while(m--)
    {
        int k;
        scanf("%d",&k);
        printf("%d\n",ans[k - 1]);
    }
    return 0;
}
1003

二分枚举:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
#define MAXN 100005
int _,num[MAXN],n;
bool have(int val)
{
    int u = num[0] - val,v;
    //cout << val << " val " << endl;
    for(int i = 1;i < n;i++)
    {
        if(num[i] <= u)v = min(num[i] + val,u + 1);
        else if(num[i] > u)v = max(num[i] - val,u + 1);
        if(v <= u)return false;
        u = v;
        //cout << u << " u v " << v << endl;
    }
    return true;
}
int solve()
{
    int l = 0,r = 1e7;
    while(l < r)
    {
        int mid = l + r >> 1;
        if(have(mid))r = mid;
        else l = mid + 1;
    }
    return l;
}
int main()
{
    for(int kcas = scanf("%d",&_);kcas <= _;kcas++)
    {
        printf("Case #%d:\n",kcas);
        scanf("%d",&n);
        for(int i = 0;i < n;i++)
            scanf("%d",&num[i]);
        int ans = solve();
        printf("%d\n",ans);
    }
}
1004:

树状数组内二分求第k大

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
#define MAXN 10005
int n;
#define lowbit(i) (i & -i)
int prefix[MAXN],order[MAXN],de[MAXN],has[MAXN];
struct Discrete
{
    int num,newnum,id;
    char op[7];
    bool operator < (const Discrete & nu)const{
        return num < nu.num;
    }
}d[MAXN];
void modify(int l,int r,int key)
{
    for(;l <= r;l += lowbit(l))
        prefix[l] += key;
}
int find_kth(int num,int n)
{
    int ans = 0,LOG = 0;
    while((1 << LOG) <= n)LOG++;
    for(int i = LOG;i >= 0;i--)
    {
        int cur = 1 << i;
        if(ans + cur > n || num <= prefix[ans + cur])
            continue;
        ans += cur;
        num -= prefix[ans];
    }
    return ans + 1;
}
void solve()
{
    int u = 0,v = 0;
    for(int i = 0;i < n;i++)
    {
        int j = order[i];
        if(d[j].op[0] == 'i')
        {
            de[u++] = d[j].newnum;
            modify(d[j].newnum,n,1);
        }
        else if(d[j].op[0] == 'o')
        {
            modify(de[v++],n,-1);
        }
        else
        {
            int num = (u - v) / 2 + 1;
            int ans = find_kth(num,n + 1);
            //cout << ans << " ans " << endl;
            printf("%d\n",has[ans]);
        }
    }
}
int main()
{
    int kcas = 1;
    while(scanf("%d",&n) != EOF)
    {
        memset(prefix,0,sizeof(prefix));
        printf("Case #%d:\n",kcas++);
        for(int i = 0;i < n;i++)
        {
            scanf("%s",d[i].op);
            d[i].id = i;
            if(d[i].op[0] == 'i')scanf("%d",&d[i].num);
            else d[i].num = 0x3f3f3f3f;
        }
        sort(d,d + n);
        for(int i = 0;i < n;i++)
        {
            order[d[i].id] = i;
            //cout << d[i].id << " id " << endl;
            if(d[i].num == 0x3f3f3f3f)continue;
            if(i == 0)d[i].newnum = 1;
            else if(d[i].num == d[i - 1].num)d[i].newnum = d[i - 1].newnum;
            else d[i].newnum = d[i - 1].newnum + 1;
            //cout << d[i].newnum << " new " << endl;
            has[d[i].newnum] = d[i].num;
        }
        solve();
    }
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值