【玲珑杯 Round#13 B】 【倍增+二分】

传送门:

http://www.ifrog.cc/acm/problem/1112?contest=1015&no=1

题意:

定义一个序列的混乱度为累加和:b[i]*v[i],b[i]为这个序列中第i小的数,v[]数组是给定的。如果当前加进来的数购车的数构成的序列的混乱度大于m,则将当前的序列扔掉,然后将变量C加一,现在给出要加进来的序列的顺序,和v[]数组,求最终C的值。

思路:

枚举左端点,二分右端点,暴力判断混乱度与M的关系,如果M为0,只能一个一个删除,那么二分貌似会将复杂度拉高,所以为了避免这种情况我们要用倍增算法确定二分区间,假设当前左端点为i,于是枚举一个k使得[i,i+2^k]刚好大于M,于是,我们要改变C的位置必定在[i+2^(k-1),i+2^k]内,然后对这个区间二分暴力判断。

代码:

#include <set>
#include <map>
#include <queue>
#include <vector>
#include <math.h>
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <string.h>
using  namespace  std;

#define ff first
#define ss second
#define pb push_back
#define ll long long
#define mod 1000000007
#define ull unsigned long long
#define mst(ss,b) memset(ss,b,sizeof(ss));
#define pl(x) cout << #x << "= " << x << endl;
const int inf = 0x3f3f3f3f;
const int N = 1e6+5;

int n, num[N];
ll m, a[N], b[N], v[N];

bool check(int l, int r){
    int len = 0;
    ll sum = 0;
    for(int i=l; i<=r; i++)b[++len] = a[i];
    sort(b+1, b+1+len);
    for(int i=1; i<=len; i++){
        sum += b[i]*v[i];
        if(sum > m)return 1;
    }
    return 0;
}

int  main(){
    //先倍增找大于m的区间,然后再二分找
    while(~scanf("%d%lld", &n, &m)){
        for(int i=1; i<=n; i++)scanf("%lld", &a[i]);
        for(int i=1; i<=n; i++)scanf("%lld", &v[i]);
        int cnt = 0;
        for(int i=1; i<=n; i++){
            int k;
            for(k=1; k+i<=n; k*=2)if(check(i, i+k))break; //k肯定多一些
            int l = i+k/2, r = i+k, ans = r; //ans要赋初值
            while(l <= r){ //找大于m
                int mid = (l+r)>>1;
                if(check(i, mid))r = mid-1, ans = mid;
                else l = mid+1;
            }
            for( ; i<=ans; i++){
                if(i == ans){
                    num[i] = ++cnt;
                    break;
                }
                num[i] = cnt;
            }
        }
        for(int i=1; i<=n; i++)printf("%d%c", num[i], i==n?'\n':' ');
    }
    return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值