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

题目概述

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

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

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

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

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

输入格式

第一行一个正整数 N,代表书架的容量。
接下来一行 N 个数,第 i 个非负整数 ai a i 代表最开始书架上第 ii 本书所描述的元素的污染值。
接下来一行一个整数M,代表事件的总数。
接下来 M 行,每行代表一个事件:
若为 0 x y,代表实习生拿了一本新书替换了 xx 位置的书,新书对应元素的污染值为 y。
若为 1 x l r,代表大科学家得到了新的结果,如果 xx 位置的书对应的元素加入了实验,那么 [l , r] 区间内的书对应的元素都必须拿来做实验。
保证大科学家的书籍总数 (N+0 操作个数 ) ≤20。
每个元素的污染值 0<=(ai,y)<=109 0 <= ( a i , y ) <= 10 9
保证 1<=x<=N1lr,1lrNM50 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 <= 20 情况下可以暴力出结果。
但此题改了条件, N<=105 N <= 10 5
我们将各个元素抽象成一个点。
由于 1<=rl+1<=N ∑ 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;
}
深度学习是机器学习的一个子领域,它基于人工神经网络的研究,特别是利用多层次的神经网络来进行学习和模式识别。深度学习模型能够学习数据的高层次特征,这些特征对于图像和语音识别、自然语言处理、医学图像分析等应用至关重要。以下是深度学习的一些关键概念和组成部分: 1. **神经网络(Neural Networks)**:深度学习的基础是人工神经网络,它是由多个层组成的网络结构,包括输入层、隐藏层和输出层。每个层由多个神经元组成,神经元之间通过权重连接。 2. **前馈神经网络(Feedforward Neural Networks)**:这是最常见的神经网络类型,信息从输入层流向隐藏层,最终到达输出层。 3. **卷积神经网络(Convolutional Neural Networks, CNNs)**:这种网络特别适合处理具有网格结构的数据,如图像。它们使用卷积层来提取图像的特征。 4. **循环神经网络(Recurrent Neural Networks, RNNs)**:这种网络能够处理序列数据,如时间序列或自然语言,因为它们具有记忆功能,能够捕捉数据中的时间依赖性。 5. **长短期记忆网络(Long Short-Term Memory, LSTM)**:LSTM 是一种特殊的 RNN,它能够学习长期依赖关系,非常适合复杂的序列预测任务。 6. **生成对抗网络(Generative Adversarial Networks, GANs)**:由两个网络组成,一个生成器和一个判别器,它们相互竞争,生成器生成数据,判别器评估数据的真实性。 7. **深度学习框架**:如 TensorFlow、Keras、PyTorch 等,这些框架提供了构建、训练和部署深度学习模型的工具和库。 8. **激活函数(Activation Functions)**:如 ReLU、Sigmoid、Tanh 等,它们在神经网络中用于添加非线性,使得网络能够学习复杂的函数。 9. **损失函数(Loss Functions)**:用于评估模型的预测与真实值之间的差异,常见的损失函数包括均方误差(MSE)、交叉熵(Cross-Entropy)等。 10. **优化算法(Optimization Algorithms)**:如梯度下降(Gradient Descent)、随机梯度下降(SGD)、Adam 等,用于更新网络权重,以最小化损失函数。 11. **正则化(Regularization)**:技术如 Dropout、L1/L2 正则化等,用于防止模型过拟合。 12. **迁移学习(Transfer Learning)**:利用在一个任务上训练好的模型来提高另一个相关任务的性能。 深度学习在许多领域都取得了显著的成就,但它也面临着一些挑战,如对大量数据的依赖、模型的解释性差、计算资源消耗大等。研究人员正在不断探索新的方法来解决这些问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值