欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

2020牛客寒假算法基础集训营4 G(概率题),H(线段树),I(经典 偏序)

程序员文章站 2022-07-13 11:02:30
...

题目链接

G-音乐鉴赏

2020牛客寒假算法基础集训营4 G(概率题),H(线段树),I(经典 偏序)

二分这个期末成绩占比重,然后判断下到达优秀的期望是否大于等于n/10

卡这题卡半天 还没搞出来

#include<bits/stdc++.h>
using namespace std;
#define ull unsigned long long
#define ll long long
const int w=1e5+5;
const ll mod=1e9+7;
int a[w];
int n;
double cheak(double x)
{
    double ans=0;//ans是统计成绩到达优秀的人数的期望值
    for(int i=1;i<=n;i++)
    {
        double k=1.0*(90-a[i]*(1-x))/x;//到达优秀所需的期末成绩k  最少需要 
        if(k>=90)//大于90 不可能了 
            continue;
        if(k<=0)//平时成绩足够优秀了,这个人已经到达优秀了 
        {
            ans++;
            continue;
        }
        ans+=(90-k)/90;//假设10分  那么 k可以取10 11 12 ...90  概率就是(90-k)/90 
    }
    return ans;
}
int main()
{
    int i,j;
    cin>>n;
    for(i=1;i<=n;i++)
        scanf("%d",&a[i]);
    double l=0,r=1;
    int t=100;
    double mid;
    while(t--)
    {
        mid=(l+r)/2;
        if(cheak(mid)>=n/10)
            l=mid;
        else
            r=mid;
    }
    printf("%.2f%\n", mid*100);
    return 0;
}

H-坐火车

2020牛客寒假算法基础集训营4 G(概率题),H(线段树),I(经典 偏序)

这题本来是水之又水的题,我居然wa了好多发,两颗线段树维护左边和右边不同颜色的车厢数就可以了。很多细节

单点更新 区间查询。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+10;
int n;
ll suml[4*N],sumr[4*N];
ll sum[4*N];
 
ll vis[N];
 
struct node
{
    int col,l,r;
}a[N];
 
void build(int id,int l,int r,int pos)
{
    if(l==r){
        sumr[id]++;
        return ;
    }
    int mid=l+r>>1;
    if(pos<=mid) build(id<<1,l,mid,pos);
    else build(id<<1|1,mid+1,r,pos);
}
 
void up(int id,int l,int r,int pos)
{
    if(l==r)
    {
        suml[id]++;
        sumr[id]--;
        sum[id]=suml[id]*sumr[id];
        return ;
    }
    int mid=l+r>>1;
    if(pos<=mid) up(id<<1,l,mid,pos);
    else up(id<<1|1,mid+1,r,pos);
    sum[id]=sum[id<<1]+sum[id<<1|1];
}
ll qu(int id,int l,int r,int ql,int qr)
{
    if(ql<=l&&r<=qr){
        return sum[id];
    }
    int mid=l+r>>1;
    ll res=0;
    if(ql<=mid) res=res+qu(id<<1,l,mid,ql,qr);
    if(qr>mid) res=res+qu(id<<1|1,mid+1,r,ql,qr);
    return res;
}
 
int main()
{
    scanf("%d",&n);
    int mx=1;
    for(int i=1;i<=n;++i) {
       int col,l,r;
       scanf("%d%d%d",&a[i].col,&a[i].l,&a[i].r);
       mx=max(mx,a[i].col);
       mx=max(mx,a[i].l);
       mx=max(mx,a[i].r);
    }
    //mx++;
    for(int i=1;i<=n;++i) {
       build(1,1,mx,a[i].col);
    }
 
    for(int i=1;i<=n;++i){
        ll t=0;
        if(a[i].l<=a[i].col&&a[i].col<=a[i].r) t=vis[a[i].col];
 
        //printf("t:%lld\n",t);
        printf("%lld ",qu(1,1,mx,a[i].l,a[i].r)-t);
        vis[a[i].col]++;
        up(1,1,mx,a[i].col);
        //if(i!=n) printf(" ");
        //else printf("\n");
    }
    return 0;
}

I-匹配星星

2020牛客寒假算法基础集训营4 G(概率题),H(线段树),I(经典 偏序)

我以为z的范围也很大,赛后看数据,怎么只有0和1

然后群友说这是经典偏序问题,我才恍然大悟,不知多久以前才搞了专题 对 偏序的,然后子集仔细想了想的确是偏序,一发AC

具体怎么偏:题解说的不错

2020牛客寒假算法基础集训营4 G(概率题),H(线段树),I(经典 偏序)

z=1的时候 采取对y进行二分查询就可以了

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
struct node
{
    int x,y,z;
}a[N];
multiset<int>st;
int n;
bool cmp(node a,node b)
{
    if(a.x!=b.x) return a.x<b.x;
    return a.y<b.y;
}
node tmp[N];
int len;
int main()
{
    cin>>n;
    for(int i=1;i<=n;++i){
        scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z);
    }
    sort(a+1,a+1+n,cmp);
    node t;
    t.x=-1;
    tmp[len]=t;
    int ans=0;
    for(int i=1;i<=n;++i){
        if(a[i].z==0) {
            if(a[i].x>tmp[len].x){
                for(int i=len;i;--i) st.insert(tmp[i].y);
                len=0;
                tmp[++len]=a[i];
            }
            else tmp[++len]=a[i];
            
        }
        else{
            if(a[i].x>tmp[len].x){
                for(int i=len;i;--i) st.insert(tmp[i].y);
                len=0;
            }
            if(st.size()==0) continue;
            
            int x=a[i].y;
            auto it=st.upper_bound(x);
            if(it!=st.begin()){
                ans++;
                --it;
                st.erase(it);
            }

        }
    }
    printf("%d\n",ans);
}