2019 ICPC Asia Yinchuan Regional (G, H)

这是第一场.先补一题,另外还有一个高精度的题目暂时不想研究.

 

G.Pot!!

首先被题面吓到了,看到一个整除的符号和一个数学式子以为是个数学题,于是没有注意到很明显的线段树的暗示.

细节:MUITIPLY的乘数x的范围是[2,10],这里面只有四个质数{2,3,5,7}.

由于序列中原本的所有数都是1,那么无论多少次操作之后,每个数都可以表示为1^a * 2^b * 3^c * 4^d * 5^e * ... * 10^j.

因此对于

 

 

 这里面的p只可能是{2,3,5,7},所以对于一个ai可以轻易求出.

 

 所以最后做法是用四个(分别存储四个质数作为因数的出现次数的)线段树维护区间信息.

照着书敲了个线段树板子,一遍就过了,问题就是板子记不住,也不算大碍吧= =

计算因数的时候用了multiset,自以为比较巧妙.

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <string>
#include <set>
using namespace std;

struct ST{
    int l, r, big, sum;
    int tag;
    #define l(x) st[x][i].l
    #define r(x) st[x][i].r
    #define big(x) st[x][i].big
    #define tag(x) st[x][i].tag
}st[400010][4];        // 2 3 5 7
int n, q;

void spread(int p, int i){
    if(!tag(p)) return;
    big(p * 2) += tag(p), big(p * 2 + 1) += tag(p);
    tag(p * 2) += tag(p), tag(p * 2 + 1) += tag(p);
    tag(p) = 0;
}
void change(int p, int l, int r, int x, int i){
    if(l <= l(p) && r >= r(p)) {
        big(p) += x;
        tag(p) += x;
        return;
    }
    spread(p, i);
    int mid = l(p) + r(p) >> 1;
    if(l <= mid) change(p * 2, l, r, x, i);
    if(r > mid) change(p * 2 + 1, l, r, x, i);
    big(p) = max(big(p * 2), big(p * 2 + 1));
}
void build(int p, int l, int r, int i){
    l(p) = l, r(p) = r;
    if(l == r) {big(p) = 0; return;}
    int mid = l + r >> 1;
    build(p * 2, l, mid, i);
    build(p * 2 + 1, mid + 1, r, i);
    big(p) = max(big(p * 2), big(p * 2 + 1)); 
}
int ask(int p, int l, int r, int i){
    if(l <= l(p) && r >= r(p)) return big(p);
    spread(p, i);
    int mid = l(p) + r(p) >> 1;
    int ret = 0;
    if(l <= mid) ret = max(ret, ask(p * 2, l, r, i));
    if(r > mid) ret = max(ret, ask(p * 2 + 1, l, r, i));
    return ret;
}

int main(){
    scanf("%d%d", &n, &q);
    for(int i = 0; i < 4; i++) build(1, 1, n, i);

    while(q--){
        string opr;
        cin >> opr;
        if(opr[1] == 'U'){        // MULTIPLY
            int l, r, x;
            cin >> l >> r >> x;
            multiset<int> ms;
            while(!(x % 2)) ms.insert(2), x /= 2;
            while(!(x % 3)) ms.insert(3), x /= 3;
            while(!(x % 5)) ms.insert(5), x /= 5;
            while(!(x % 7)) ms.insert(7), x /= 7;
            for(const auto &i : ms)
                switch(i){
                    case 2: change(1, l, r, 1, 0); break;
                    case 3: change(1, l, r, 1, 1); break;
                    case 5: change(1, l, r, 1, 2); break;
                    case 7: change(1, l, r, 1, 3); break;
                }
        }else{                    // MAX
            int l, r;
            cin >> l >> r;
            int ans = 0;
            for(int i = 0; i < 4; i++) ans = max(ans, ask(1, l, r, i));
            cout << "ANSWER " << ans << endl;
        }
    }

    return 0;
}
G

 

H - Delivery Route

不是正解,用SPFA优化卡过去了.

给出一张含有负权边的图,求单源最短路,1<=n<=25000,2<=m<=150000.

有负边,SPFA复杂度又不够,于是SLF优化.

STL依赖症被治好了,手写双端队列,链式向前星.

关于这个SLF的原理,我还在找博文,再看看.

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
using namespace std;
#define INF 0x3F3F3F3F

struct E {
    int to = 0, wei = 0, nxt = 0;
} e[150010];
int head[25010], ind = 1;
int n, x, y, s, dist[25010];
int q[20000010], l = 1e7, r = 1e7, val = 0;
bool used[25010];

inline void add(int x, int y, int w) {
    e[ind].to = y;
    e[ind].wei = w;
    e[ind].nxt = head[x];
    head[x] = ind++;
}
inline int read() {    
    char ch = getchar();
    int x = 0, f = 1;
    while (ch > '9' || ch < '0') {
        if (ch == '-') f = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9') {
        x = x * 10 + ch - '0';
        ch = getchar();
    }
    return x * f;
}

int main() {
    n = read(), x = read(), y = read(), s = read();
    while (x--) {
        int a = read(), b = read(), c = read();
        add(a, b, c);
        add(b, a, c);
        val += 2 * c;
    }
    while (y--) {
        int a = read(), b = read(), c = read();
        add(a, b, c);
        val += c;
    }
    val = sqrt(val) / 100;

    memset(dist, 0x3F, sizeof(dist));
    q[l] = s;
    dist[s] = 0;
    used[s] = true;
    while (l <= r) {
        int cur = q[l];
        l++;
        used[cur] = false;

        for (int i = head[cur]; i; i = e[i].nxt)
            if (dist[e[i].to] > dist[cur] + e[i].wei) {
                dist[e[i].to] = dist[cur] + e[i].wei;
                if (!used[e[i].to]) {
                    used[e[i].to] = true;
                    if (l <= r && dist[e[i].to] < dist[q[l]] + val)
                        q[--l] = e[i].to;
                    else
                        q[++r] = e[i].to;
                }
            }
    }

    for (int i = 1; i <= n; i++)
        if (dist[i] != INF)
            printf("%d\n", dist[i]);
        else
            puts("NO PATH");

    return 0;
}
H

 

posted @ 2021-05-20 20:35  goverclock  阅读(46)  评论(0编辑  收藏  举报