首页 > 代码库 > BestCoder Round #91

BestCoder Round #91

传送门:http://acm.hdu.edu.cn/search.php?field=problem&key=BestCoder+Round+%2391&source=1&searchmode=source

A题:给你n种字母,每种字母有个权值vali,共cnti个,现在让你在里面挑出任意数量的字符,组合成一个字符串,该字符串的权值的计算方式为val1*1+val2*2+……+valn*n,让你输出字符串最大的权值是多少。这题很容易会有一个错误的贪心,就是把val为负的舍去,然后val从小到大选择。事实上负值时可以选的,比如字符1的权值为-1,字符2的权值为2,字符3的权值为3,那么如果我不选字符1,总权值为2*1+3*2=8,小于选了字符1的权值-1*1+2*2+3*3=12,所以这种贪心是错的。正解是先按val对字符排序,很明显,val大的字符如果不选,val小的就一定不会选。也即是,如果字符ch选了,权值比它大的肯定也会选。那假设它选了,总权值就会增加valch+valch+1,valch+2……valn,因此只要判断valch+valch+1,valch+2……valn是不是大于0,就能确定ch到底要不要选了。可以预处理下后缀和,然后直接扫一遍。

技术分享
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
#include <string>
#include <stack>
#include <map>
#include <set>
#include <bitset>
#define X first
#define Y second
#define clr(u,v); memset(u,v,sizeof(u));
#define in() freopen("data","r",stdin);
#define out() freopen("ans","w",stdout);
#define Clear(Q); while (!Q.empty()) Q.pop();
#define pb push_back

using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int maxn = 1e5 + 10;
const int INF = 0x3f3f3f3f;
pii N[100];
vector <int> V;
int sum[maxn];

int main()
{
    int T;
    scanf("%d", &T);
    while (T--)
    {
        V.clear();
        int n;
        scanf("%d", &n);
        for (int i = 0; i < n; i++)
        {
            scanf("%d%d", &N[i].X, &N[i].Y);
            while (N[i].Y--)
                V.pb(N[i].X);
        }
        sort(V.begin(), V.end());
        sum[V.size()] = 0;
        for (int i = V.size() - 1; i >= 0; i--)
            sum[i] = sum[i+1] + V[i];
        ll ans = 0, k = 1;
        for (int i = 0; i < V.size(); i++)
            if (V[i] >= 0 || V[i] + sum[i+1] >= 0)
            {
                ans += k * V[i];
                k++;
            }
        printf("%I64d\n", ans);
    }
    return 0;
}
View Code

B题:有n种植物,每种植物有个适宜温度区间,如果温度适宜,它可以提供ai的研究价值,如果温度大于适宜温度的上限,它可以提供bi的研究价值,如果温度小于适宜温度的下限,它可以提供ci的研究价值。现在让你找到一个温度,使得总研究价值最大,温度可以为任意实数。输出最大总研究价值。先离散化一下温度,然后线段树维护下最大研究价值。注意由于温度是实数,所以离散的时候要,两个数之间要多加一个空位,用于浮点数的统计。

技术分享
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
#include <string>
#include <stack>
#include <map>
#include <set>
#include <bitset>
#define X first
#define Y second
#define clr(u,v); memset(u,v,sizeof(u));
#define in() freopen("data","r",stdin);
#define out() freopen("ans","w",stdout);
#define Clear(Q); while (!Q.empty()) Q.pop();
#define pb push_back
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1

using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
const int maxn = 2e5 + 10;
const int inf = 0x3f3f3f3f;
struct node1
{
    int l, r, a, b, c;
} N[maxn];
vector<pii> V;
LL add[maxn<<2];
LL Max[maxn<<2];
void PushUp(int rt)
{
    Max[rt] = max(Max[rt<<1] , Max[rt<<1|1]);
}
void PushDown(int rt, int m)
{
    if (add[rt])
    {
        add[rt<<1] += add[rt];
        add[rt<<1|1] += add[rt];
        Max[rt<<1] += add[rt];
        Max[rt<<1|1] += add[rt];
        add[rt] = 0;
    }
}

void update(int L, int R, int c, int l, int r, int rt)
{
    if (L <= l && r <= R)
    {
        add[rt] += c;
        Max[rt] += c;
        return ;
    }
    PushDown(rt , r - l + 1);
    int m = (l + r) >> 1;
    if (L <= m) update(L , R , c , lson);
    if (m < R) update(L , R , c , rson);
    PushUp(rt);
}
LL query(int L, int R, int l, int r, int rt)
{
    if (L <= l && r <= R)
    {
        return Max[rt];
    }
    PushDown(rt , r - l + 1);
    int m = (l + r) >> 1;
    LL ret = 0;
    if (L <= m) ret = max(ret, query(L , R , lson));
    if (m < R) ret = max(ret, query(L , R , rson));
    return ret;
}

void init()
{
    V.clear();
    clr(add, 0);
    clr(Max, 0);
}

int main()
{
    int T;
    scanf("%d", &T);
    while (T--)
    {
        init();
        V.pb(make_pair(0,-1));
        int n;
        scanf("%d", &n);
        for (int i = 0; i < n; i++)
        {
            scanf("%d%d%d%d%d", &N[i].l, &N[i].r, &N[i].a, &N[i].b, &N[i].c);
            V.pb(make_pair(2 * N[i].l , i));
            V.pb(make_pair(2 * N[i].r , i));
            V.pb(make_pair(2 * N[i].l + 1, -1));
            V.pb(make_pair(2 * N[i].r + 1, -1));
            N[i].l = N[i].r = -1;
        }
        int pos = 1;
        sort(V.begin(), V.end());
        for (int i = 0; i < V.size(); i++)
        {
            if (V[i].Y == -1)
            {
                pos++;
                continue;
            }
            if (N[V[i].Y].l == -1)
                N[V[i].Y].l = pos;
            else N[V[i].Y].r = pos;
            if (i != V.size() - 1 && V[i].X == V[i+1].X) continue;
            pos++;
        }
        pos--;
        for (int i = 0; i < n; i++)
        {
            if (N[i].l - 1 >= 1) update(1, N[i].l - 1, N[i].c, 1, pos, 1);
            update(N[i].l, N[i].r, N[i].a, 1, pos, 1);
            if (N[i].r + 1 <= pos) update(N[i].r + 1, pos, N[i].b, 1, pos, 1);
        }
        printf("%I64d\n", query(1, pos, 1, pos, 1));
    }
    return 0;
}
View Code

剩下两题不会了= =,这场能升分得益于A题的错误贪心发现得早。。没造成太多罚时损失,遗憾是手速太慢没hack到人。B题知道做法,但是调线段树调了半天,还没注意到可以是实数,样例一直调不过,决定去刷下线段树专题,,补补线段树。

2017-01-23 22:09:00

BestCoder Round #91