[补题] xjtu小学期-day2 贪心与分治

版权声明:欢迎转载评论 https://blog.csdn.net/m0_37809890/article/details/81278530

说实话这天的题很不友好,而且和贪心分治感觉联系不是很大

Nike的区间问题

给一个1~n的排列a1,a2,⋯,an。你希望知道有多少个子区间[l,r],满足u≤max(al,al+1,⋯,ar−1,ar)≤v

在一个排列中,区间最大值为k的区间个数等于
( k k ) ( k k )
从1到n依次访问每个数的位置,用并查集依次维护每个数左边和右边第一个比它本身大的数的位置.
将u到v的结果相加即为答案.
复杂度O(n)

int save[M]; //下标是位置,存储的是值
int loca[M]; //下标是值,存储的是位置
int lef[M],rig[M];  //下标是位置,存储的是位置
int getfa(int *arr,int p)
{
    return arr[p]==p?p:arr[p]=getfa(arr,arr[p]);
}
int main(void)
{
    int n,u,v;
    while(scanf("%d%d%d",&n,&u,&v)!=EOF)
    {
        save[0] = save[n+1] = MOD;
        lef[n+1] = rig[n+1] = n+1;
        for(int i=1;i<=n;i++)
        {
            save[i] = read();
            loca[save[i]] = i;
            lef[i] = rig[i] = i;
        }
        ll ans = 0;
        for(int num=1;num<=v;num++)
        {
            int id = loca[num];
            lef[id] = getfa(lef,id-1);
            rig[id] = getfa(rig,id+1);
            if(num>=u)
                ans += (id-lef[id])*(rig[id]-id);
        }
        cout << ans << endl;
    }

    return 0;
}

Nike的序列问题

给定一个数列,求2^n个子序列和的中位数.

一个结论题,设m=数列之和/2,则对于每个子序列,总有一个互补的子序列使得它们的和为2m且一个小于m,一个大于m.所以m就是答案

    int n;
    while(scanf("%d",&n)!=EOF)
    {
        ll ans=0;
        while(n--)
            ans+=read();
        cout << ans/2 << endl;
    }

Nike开加油站

从n个数里删去m个,使得排序后数之间最小的差最大,求这个最大的最小差.

最小值最大问题,二分.

int save[M];
int check(int p, int n, int m)
{
    int now = 0;
    for(int i=0;i<=n;i++)
    {
        if(save[i] - now < p)
            m--;
        else
            now = save[i];
    }
    return m>=0;
}
int main(void)
{
    int len=read(),n=read(),m=read();
    for(int i=0;i<n;i++)
        save[i] = read();
    save[n] = len;
    int l=1,r=len,ans=-1;
    while(l<=r)
    {
        int mid = (l+r)>>1;
        if(check(mid,n,m)) ans = mid, l = mid + 1;
        else r = mid - 1;
    }
    printf("%d\n",ans );

    return 0;
}

复习一下二分的写法

猜你喜欢

转载自blog.csdn.net/m0_37809890/article/details/81278530
今日推荐