2018 计蒜之道 初赛第一场 C 百度科学家

题目概述

百度有一位非常有名的大科学家,这位大科学家有很多藏书。

大科学家有一个书架,书架可以看成一个长度为 N 的序列,一开始里面放着 N 本书,每本书都记载了一个特定元素的信息,书中的元素各不相同。

大科学家会先进行若干次研究,最后进行一次科学实验,这次实验需要选取一些元素放在一起来进行。每次研究,大科学家会从书架上的某些位置抽出一些书来看,然后得出“如果 x 位置上的书对应的元素被拿来做实验了,那么区间[l , r]位置上的书对应的元素也必须拿来做实验,否则会爆炸”这样的结论。

大科学家有不止 N 本书(也就是说世界上有不止 N 种元素),但是他自己没时间给书架换书,所以他雇了一个实习生,这个实习生会时不时地拿出一本从来没被放上书架的书,然后替换掉书架上某个位置原来的书(所以对于大科学家得到的两次看似一样的研究结果,可能由于书架上的书被换了,它们的实质内容可能不一样)。

每本书还记载着对应元素的非负污染值,大科学家希望在完成一次科学实验的前提下(不能不选任何元素),这次实验的总污染值最小。作为一个旁观者,你能看到科学家做的所有研究结果以及实习生换书的顺序,然后你需要告诉大科学家,这个最小总污染值是多少。

输入格式

第一行一个正整数 N,代表书架的容量。
接下来一行 N 个数,第 i 个非负整数 a i 代表最开始书架上第 ii 本书所描述的元素的污染值。
接下来一行一个整数M,代表事件的总数。
接下来 M 行,每行代表一个事件:
若为 0 x y,代表实习生拿了一本新书替换了 xx 位置的书,新书对应元素的污染值为 y。
若为 1 x l r,代表大科学家得到了新的结果,如果 xx 位置的书对应的元素加入了实验,那么 [l , r] 区间内的书对应的元素都必须拿来做实验。
保证大科学家的书籍总数 (N+0 操作个数 ) ≤20。
每个元素的污染值 0 <= ( a i , y ) <= 10 9
保证 1 <= x <= N 1 l r , 1 l r N M 50

输出格式

输出一个整数,代表最小总污染值。

样例解释

一开始书架上有 55 本书,我们记这些元素的编号顺次为 1,2,3,4,5,他们的污染值分别为 1,10,100,1000,10000。

一共有 4 个事件:

大科学家发现,选了元素 1 就必须选元素 3,4。
大科学家发现,选了元素 3 就必须选元素 5。
实习生拿了一本新书,我们记这个新元素的编号为 6,他的污染值为 0,替换掉现在书架上的第 3 本书,现在书架上的 5 本书对应元素为 1,2,6,4,5。
大科学家发现,选了元素 6(因为它在位置 3 上)就必须选元素 1,2。
于是在所有可能的方案中,单选一个元素 2 来做实验是总污染值最小的,因为如果选择元素 1 或元素 6,都存在一些绑定关系使得总污染值不可能比10 更小。

样例输入

5
1 10 100 1000 10000
4
1 1 3 4
1 3 5 5
0 3 0
1 3 1 2

样例输出

10

解题方法

经过前面B题的铺垫, 我们已经知道了在 N <= 20 情况下可以暴力出结果。
但此题改了条件, N <= 10 5
我们将各个元素抽象成一个点。
由于 1 <= r l + 1 <= N ,在本题中。
我们依旧不需要考虑加边情况的复杂度,因为至多只有N条边。
算法要求在O(NlogN)以及更低的复杂度情况下进行。
那么考虑我们在B题中所考虑的O(N^2),真正的使复杂度爆炸的是搜索的部分。
由于对每个点进行深搜,多了很多不必要的搜索。
显然,这个时候该记忆化了。
但由于有环的存在, 直接记忆化是绝对行不通的。
那把环去掉就好了, tarjan就是用来做这种事情的。
缩环后, 原来的图变成了一个DAG。
就可以在DAG上跑记忆化搜索了。
复杂度是O(N)的

代码

#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<algorithm>
#include<vector>
#define inf 0x7fffffff
using namespace std;
typedef long long LL;
const int maxn = 1e5 + 7;

LL M[maxn], rec[maxn], sums[maxn];
struct edge {
    int to, next;
}map[maxn*2];

vector<int> vec[maxn];
vector<int> edg[maxn];

int visit[maxn];
int dfn[maxn], low[maxn], times = 0, top = 0;
int instack[maxn], stack[maxn], sz = 0, belong[maxn];

void tarjan(int x) {
    int v;
    dfn[x]=low[x]=++times;
    instack[x]=true;
    stack[++top] = x;
    for(int i=0;i<vec[x].size();++i) {
        v = vec[x][i];
        if(!dfn[v]) {
            tarjan(v);
            if(low[v] < low[x]) low[x] = low[v];
        }
        else if (instack[v] && dfn[v]<low[x]) low[x]=dfn[v];
    }
    if(dfn[x]==low[x]) {
        sz++;
        sums[sz] = 0;
        do {
            v=stack[top--];
            instack[v]=false;
            belong[v]=sz;
            sums[sz] += M[v];
        }
        while(v!=x);
    }
}

void solve(int n) {
    int i;
    sz = times = top = 0;
    memset(dfn, 0, sizeof(dfn));
    memset(sums, -1, sizeof(sums));

    for(i=1;i<=n;++i)
        if(!dfn[i]) tarjan(i);
}

LL a[maxn], lnk[maxn];
LL dfs(int x) {
    if(rec[x] != -1) return(rec[x]);
    LL sum = sums[x];
    for(int i=0;i<edg[x].size();++i) {
        sum += (rec[edg[x][i]] = dfs(edg[x][i]));
    }
    return((rec[x] = sum));
}

int main() {
    std::ios::sync_with_stdio(false);
    int n, m, op, x; LL t;
    cin >> n;
    for(int i=1;i<=n;++i) {
        cin >> a[i];
        lnk[i] = i;
    }
    cin >> m;
    LL ans = 1e18;
    for(int i=1;i<=n;++i) M[i] = a[i], vec[i].clear();
    int ct = n+1;

    while(m--) {
        cin >> op;
        if(op == 1) {
            int ls, rs;
            cin >> x >> ls >> rs;
            for(int i=ls;i<=rs;++i)
                vec[lnk[x]].push_back(lnk[i]);
        } else {
            cin >> x >> t;
            lnk[x] = ct++;
            M[lnk[x]] = t;
            vec[lnk[x]].clear();
        }
    }

    solve(ct-1);


    for(int i=1;i<ct;++i) {
        for(int j=0;j<vec[i].size();++j)
            if(belong[i] != belong[vec[i][j]]) {
                edg[belong[i]].push_back(belong[vec[i][j]]);
            }
    }

    memset(rec, -1, sizeof(rec));
    for(int i=1;i<=sz;++i) {
        memset(visit, 0, sizeof(visit));
        ans = min(ans, dfs(i));
    }
    cout << ans << endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_39859264/article/details/80295394