Educational Codeforces Round 44 D, E

D. Sand Fortress

题意:找长度为k的序列,使得序列之和大于等于n,且|A(i)-A(i-1)| <= 1, A0 <= H,求最小的k。
由于k与sum成单增关系,可以二分k的值来找最小的符合条件的k,check采用等差数列求和。
注意要先确定上界避免数据过大
由于mid = l + (r - l)/2 = r - (r-l)/2 属于 (l, r)
为了避免无限循环check之后r != mid + 1, l != mid-1即可
本题中我选取的区间是[l, r], 找符合条件的最小值,l初始值为1

#include 

using namespace std;
const int maxn = 100005;
typedef long long ll;

ll n, H;

ll area(ll l, ll r) { return (l + r)*(abs(r - l) + 1)/2; }

bool check(ll mid) {
    ll s = 0;
    if(mid <= H) {
        s = area(1, mid);
    }
    else {
        mid += H - 1;
        if(mid & 1) s = area(H, mid/2 + 1) + area(mid/2, 1);
        else s = area(H, mid/2) + area(mid/2, 1);
    }
    return s >= n;
}

int main() {
    //freopen("in.txt", "r", stdin);
    //freopen("out.txt", "w", stdout);
    while(cin >> n >> H) {
        ll l = 1, r = 2*sqrt(n) + 1, mid;
        while(r != l) {
            mid = l + (r - l)/2;
            //printf("l = %lld, r = %lld, mid = %lld\n", l, r, mid);
            if(check(mid)) r = mid;
            else l = mid + 1;
        }
        //printf("l = %lld, r = %lld, mid = %lld\n", l, r, mid);
        cout << r << endl;
    }
    return 0;
}

E. Pencils and Boxes

题意:对n个数进行划分,每个区间至少k个数,区间内,|ai-aj| <= d,判定是否存在这种划分。
朴素做法:sort后,令dp(i) = 1代表区间[1, i]上有解。进行O(n^2)dp。

dp[k-1] = a[k-1] - a[1] <= d;
for(int i = k; i <= n; ++i) {
    dp[i] = 0;
    for(int j = k - 1; j < i; ++j) {
        if(i - j >= k) {    //[j + 1, i]作为新区间
            dp[i] |= a[i] - a[j+1] <= d && dp[j];
        }                   //[1, i]作为一个区间
        dp[i] |= a[i] - a[1] <= d;
    }
    //令dp(0) = 1, 合并两种情况
}

dp[0] = 1;
for(int i = 1; i <= n; ++i) {
    dp[i] = 0;
    for(int j = 0; j < i; ++j) {
        dp[i] |= i - j >= k && a[i] - a[j+1] <= d && dp[j];
    }
}

优化:在满足前两个条件的区间内查询是否有dp(j) = 1即可

树状数组维护

#include 

#define lowbit(x) x&(-x)

using namespace std;
const int maxn = 500005;
int a[maxn];
bool dp[maxn];
int bit[maxn];
int n, k, d;

void add(int i) {
    i++;
    while(i <= n + 1) {
        bit[i]++;
        i += lowbit(i);
    }
}

int sum(int i) {
    i++;
    int ret = 0;
    while(i > 0) {
        ret += bit[i];
        i -= lowbit(i);
    }
    return ret;
}

bool query(int l, int r) {
    if(l > r) return false;
    return sum(r) - sum(l-1);
}

int main() {
    while(cin >> n >> k >> d) {
        for(int i = 1; i <= n; ++i) {
            cin >> a[i];
        }
        sort(a + 1, a + n + 1);
        //for(int i = 1; i <= n; ++i) printf("%d\n", a[i]);
        dp[0] = 1;
        add(0);
        int j = 0;
        for(int i = 1; i <= n; ++i) {
            while(j < i && a[i] - a[j + 1] > d) ++j;
            int l = j, r = i - k;
            //printf("l = %d, r = %d\n", l, r);
            dp[i] = query(l, r);
            if(dp[i]) add(i);
            //printf("dp[%d] = %d\n", i, dp[i]);
        }
        puts(dp[n] ? "YES" : "NO");
    }
    return 0;
}

单调队列维护,q中放dp(i) = 1的i

#include 

using namespace std;
const int maxn = 500005;
int a[maxn], q[maxn];
int n, k, d;

int main() {
    while(cin >> n >> k >> d) {
        for(int i = 1; i <= n; ++i) {
            cin >> a[i];
        }
        sort(a + 1, a + n + 1);
        int l = 0, r = 1;
        q[l] = 0;
        for(int i = k; i <= n; ++i) {
            while(l < r && a[i] - a[q[l] + 1] > d) l++;
            if(l < r && i - q[l] >= k) q[r++] = i;
        }
        puts(q[r - 1] == n ? "YES" : "NO");
    }
    return 0;
}

你可能感兴趣的:(Codeforces)