codeforces round 625

B

题意是从已知序列中找一个严格递增的子序列,并且这个子序列中任意相邻的两个元素之差等于它们在原序列中的位置之差,求所有满足条件的子序列中元素和的最大值。

条件用公式表示:对于满足要求的子序列中任意两个相邻元素a1,a2(位置分别是pos1,pos2),都有a1-a2=pos1-pos2(a1<a2,严格递增)。
假设我们找到一条满足的,那他的魅力值其实就是来看就是由同一个数值不断++而来的例如

位置2=3,位置4=5,满足要求,那其实他们都是从位置1=2起源的;

所以只需记录ai-i就行

int n;
int b[M];
ll c[M];
 
void run(){
    for(int i = 1; i <= n; i++) {
        cin >> b[i];
        c[b[i] - i + N] += b[i];
    }
    ll ans = 0;
    for(int i = 1; i < M; i++) {
        ans = max(ans, c[i]);   
    }
    cout << ans << '
';
}

  C

题意是给你一个只含小写字母的字符串,每次你可以找一个字符,只要它的相邻字符中存在一个字符比它自己的ascci码小1,那么你就可以删除这个字符,问你最多能删多少个。

由于数据量非常小,只有100,所以直接暴力模拟就行了。稍微加点贪心思想,先删除字典序大的字符,从字母z到字母b的顺序删除(字母a不存在比自己ascci码小1的小写字母)。还有就是注意遍历字符串的时候正反都要遍历一次,防止 bbbba 这种情况误判。

#include <bits/stdc++.h>
using namespace std;
string s;
char ch;
int n,ans,vis[150];
int main()
{
    ios::sync_with_stdio(false);
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>ch;
        s+=ch;
        vis[ch]++;
    }
    for(ch='z';ch>='b';ch--)
    {
        if(!vis[ch])continue;
        for(int i=0;i<s.size();i++)
        {
            if(s[i]==ch)
            {
                if((i+1<s.size()&&s[i]-1==s[i+1])||(i-1>=0&&s[i]-1==s[i-1]))
                    s.erase(s.begin()+i),i--,ans++;
            }
        }
        for(int i=s.size()-1;i>=0;i--)//反向遍历,防止bbbba这种情况误判
        {
            if(s[i]==ch)
            {
                if((i+1<s.size()&&s[i]-1==s[i+1])||(i-1>=0&&s[i]-1==s[i-1]))
                    s.erase(s.begin()+i),i++,ans++;
            }
        }
    }
    printf("%d
",ans);
    return 0;
}

  D

题意: 给出一个有向图和一个人的行动路径, 这个人每次移动前导航仪会给出从当前点到终点的一条最短路线, 如果这个人移动的路线与之不符, 导航仪会重新生成从下一个点出发到终点的最短路线. 问导航仪生成新路线的最小和最大次数.

思路: bfs求出所有点到终点的最短距离. 如果这个人移动时距离终点不是-1, 那他这次移动一定不在最短路线上; 否则, 检查是否有其他使距离-1的路线, 如果有, 那么就知道导航仪可能会重新生成路线.
view code




#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define inc(i, l, r) for (int i = l; i <= r; i++)

const int maxn = 1e6 + 5;
const int inf = 0x3f3f3f3f;

vector<int> g[maxn];
vector<int> rg[maxn];
int a[maxn], d[maxn], vis[maxn];
int n, m, u, v, k;

int main() {
    memset(d, 63, sizeof(d));
    cin >> n >> m;
    inc(i, 1, m) {
        cin >> u >> v;
        rg[u].push_back(v);
        g[v].push_back(u);
    }
    cin >> k;
    inc(i, 1, k) cin >> a[i];
    queue<int> que;
    que.push(a[k]);
    d[a[k]] = 0;
    vis[a[k]] = 1;
    while (que.size()) {
        int p = que.front();
        que.pop();
        inc(i, 0, (int)g[p].size() - 1) {
            if (!vis[g[p][i]]) {
                d[g[p][i]] = d[p] + 1;
                que.push(g[p][i]);
                vis[g[p][i]] = 1;
            }
        }
    }
    int res1 = 0, res2 = 0;
    for (int i = 1; i < k; i++) {
        int now = a[i], nxt = a[i + 1];
        if (d[now] != d[nxt] + 1)
            res1++, res2++;
        else
            inc(j, 0, (int)rg[now].size() - 1) {
                if (d[rg[now][j]] + 1 == d[now] && rg[now][j] != nxt) {
                    res2++;
                    break;
                }
            }
    }
    cout << res1 << " " << res2;
}

  

题意: 给出 n 个武器, m 个防具, 分别有攻击力 ai 和防御力 bi, 购买该装备需要的金币ci, 还有 p 个怪兽, 分别具有防御力 xi, 攻击力 yi, 打败它获得的金币 ci. 现要求从中武器和防具中各选出恰好一个, 然后就可以打败所有满足 ai > xj 且 bi > yj 的怪兽并获得 cj. 求最大获利.

思路: 预处理攻击力和防御力达到 x 最少需要支付的金币数 atk[x], def[x]. 对所有怪兽排序(不妨以 xi 为第一关键字), 扫描一遍, 维护这样的线段树: 防御力为 x 时的最大获利, 每个节点初始值为 -def[x], 表示为了该防具需要支付的金币数. 每扫过一只怪兽, 防御力足以打败该怪兽的范围就增加 ci, 而武器攻击力为当前怪兽的 xi + 1, 这样可以确保前面扫描过的怪兽都满足 ai > xj.

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define inc(i, l, r) for (int i = l; i <= r; i++)
#define dec(i, l, r) for (int i = l; i >= r; i--)
#define pii pair<int, int>
#define fi first
#define se second
#define pb push_back

const int maxn = 1e6 + 5;
const int inf = 0x3f3f3f3f;

int n, m, p;
int atk[maxn], def[maxn];
struct node {
    int a, b, c;
    bool operator<(const node &o) const {
        if (a == o.a) return b < o.b;
        return a < o.a;
    }
} mos[maxn];
int x, y, c, matk, mdef;

ll f[4 * maxn], mv[4 * maxn];

void up(int k) { mv[k] = max(mv[k << 1], mv[k << 1 | 1]); }
void down(int k) {
    f[k << 1] += f[k], f[k << 1 | 1] += f[k];
    mv[k << 1] += f[k], mv[k << 1 | 1] += f[k];
    f[k] = 0;
}
void build(int k, int l, int r) {
    if (l == r) {
        mv[k] = -def[l];
        return;
    }
    int mid = l + r >> 1;
    build(k << 1, l, mid);
    build(k << 1 | 1, mid + 1, r);
    up(k);
}
void add(int k, int l, int r, int val, int a, int b) {
    if (a <= l && r <= b) {
        mv[k] += val, f[k] += val;
        return;
    }
    down(k);
    int mid = l + r >> 1;
    if (a <= mid) add(k << 1, l, mid, val, a, b);
    if (b > mid) add(k << 1 | 1, mid + 1, r, val, a, b);
    up(k);
}

int main() {
    memset(atk, 127, sizeof(atk));
    memset(def, 127, sizeof(def));
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cin >> n >> m >> p;
    inc(i, 1, n) {
        cin >> x >> c;
        atk[x] = min(atk[x], c);
        matk = max(x, matk);
    }
    dec(i, matk - 1, 1) atk[i] = min(atk[i], atk[i + 1]);
    inc(i, 1, m) {
        cin >> x >> c;
        def[x] = min(def[x], c);
        mdef = max(x, mdef);
    }
    dec(i, mdef - 1, 1) def[i] = min(def[i], def[i + 1]);
    build(1, 1, mdef);
    inc(i, 0, p - 1) {
        cin >> x >> y >> c;
        mos[i] = {x, y, c};
    }
    sort(mos, mos + p);
    ll res = -atk[1] - def[1];
    inc(i, 0, p - 1) {
        if (mos[i].b < mdef) add(1, 1, mdef, mos[i].c, mos[i].b + 1, mdef);
        if (mos[i].a < matk) res = max(res, mv[1] - atk[mos[i].a + 1]);
    }
    cout << res;
}

  

原文地址:https://www.cnblogs.com/hgangang/p/12402413.html