Codeforces Round 888 (Div. 3)

E. Nastya and Potions

题意: 有n种药剂,其中你有p种药剂是免费的,其中一种药剂可以通过其他的药剂混合而成或者通过购买花费金币获得。给定每个药剂的配方,若无配方则只能通过购买获得。求获得每个药剂的最小金币数。数据保证每一种药剂不可能通过任何混合的方式合成自己。请输出获得每种药剂的最小花销。(红色的字体保证了是无环图)

思路:典型的有向无环图的记忆化搜索,有人说dp其实都一样,我们通过记忆化搜索(dfs) 的方法来确定他每一种原料的最小花销,这样就能得到通过合成路线相加获得该药剂的最小花销。之后我们将这个价格和市场价格做比对,保留最小值即可,并记得标记已经得到的答案,已便用它来更新答案

#include <bits/stdc++.h>
using namespace std;
#define pi acos(-1)
#define lowbit(x) x & (-x)
#define X first
#define Y second
#define endl "\n"
#define int long long
#define pb push_back
typedef pair<int, int> PII;
#define max(a, b) (((a) > (b)) ? (a) : (b))
#define min(a, b) (((a) < (b)) ? (a) : (b))
#define Ysanqian ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
const int N = 1e6 + 10, M = 1010, inf = 0x3f3f3f3f, mod = 998244353;
vector<int> g[N];
bool st[N];
int n, k;
int w[N];
void dfs(int u)
{
    int res = 0;
    if (g[u].size() == 0) // 如果该点只能购买
    {
        st[u] = 1; // 标记直接返回即可,它的花费就是它的价格
        return;
    }
    for (auto ed : g[u]) // 遍历u的制作要求
    {
        if (!st[ed]) // 未遍历过
        {
            dfs(ed);      // 继续遍历
            res += w[ed]; // 然后后加上这个点得贡献
        }
        else
            res += w[ed]; // 遍历过直接加上即可
    }
    st[u] = 1;             // 标记走过了最后再标记更新
    w[u] = min(w[u], res); // 跟新答案
}
void solve()
{
    memset(st, false, sizeof st); // 一定要初始化
    cin >> n >> k;
    for (int i = 1; i <= n; i++) // 一定要初始化,把图清空
        g[i].clear();
    for (int i = 1; i <= n; i++)
        cin >> w[i];
    for (int i = 1; i <= k; i++)
    {
        int x;
        cin >> x;
        w[x] = 0;     // 如果拥有无限的这种药水,那就价值为零
        st[x] = true; // 并且标记这种药水,不用再dfs了
    }
    for (int i = 1; i <= n; i++)
    {
        int x;
        cin >> x; // 读入每种药水的制作要求
        for (int j = 1; j <= x; j++)
        {
            int v;
            cin >> v;
            g[i].pb(v);
        }
    }
    for (int i = 1; i <= n; i++)
    {
        if (!st[i]) // 如果没有计算过就dfs,在输出
            dfs(i);
        cout << w[i] << ' '; // 否则直接输出
    }
    cout << endl;
}
signed main()
{
    Ysanqian;
    int T;
    // T = 1;
    cin >> T;
    while (T--)
        solve();
    return 0;
}

F. Lisa and the Martians

题意:给定一个整数k,给定n个整数,其中每个数a[ i ] < 2^{_{k}}。从中选取两个数不能相等,和一个任意数x(x的值大于等于0,且< 2^{_{k}}。求(a_{i} \oplus x)\&(a_j \oplus x)的最大值。

思路:假设(a_{i} \oplus x)\&(a_j \oplus x) = res 。对于每一位来说(用m来说),若a_{im} =a_{jm}= 0,则res_{m}= 1,若a_{im}= a_{jm}= 1,则res_{m}= 0(m为二进制所在位数)。

因为如果a_{i} 与a_{j}某一位不相同,那么这一位不论异或1还是0,最后都会得到一个1和一个0,然后相与为0,只有某一位相同才能通过改变x在该位的值使得这一位异或后等于1.

述就相当于a_{i}  同或 a_{j} 后最大,那么也就是 a_{i} 异或 a_{j}  后最小。

后有个结论,n个数的最小异或对答案就是排序后最小的相邻异或和。(这个是一位大佬赛后告诉的,本来想写字典树来着,结果发现不会。。)

可以提醒一下,会补字典树的

那我们就让他们不行等的位上的res为0好了,其实无所谓,就是图个方便

res = ((1 << k) - 1) \oplus (a_{i} \oplus a_{j})

#include <bits/stdc++.h>
using namespace std;
#define pi acos(-1)
#define xx first
#define yy second
#define endl "\n"
#define int long long
#define pb push_back
typedef pair<int, int> PII;
#define max(a, b) (((a) > (b)) ? (a) : (b))
#define min(a, b) (((a) < (b)) ? (a) : (b))
#define Ysanqian ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
const int N = 1e6 + 10, M = 1010, inf = 0x3f3f3f3f, mod = 998244353;
int n, k;
PII a[N];
bool cmp(PII a, PII b)
{
    return a.xx < b.xx;
}
void solve()
{
    int minn = 2e9;
    cin >> n >> k;
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i].xx;
        a[i].yy = i;
    }
    sort(a + 1, a + 1 + n, cmp);
    int idx = 2;
    for (int i = 2; i <= n; i++)
    {
        if (minn > (a[i].xx ^ a[i - 1].xx))
        {
            minn = (a[i].xx ^ a[i - 1].xx);
            idx = i;
        }
    }
    int m = ((1 << k) - 1) ^ a[idx].xx;
    cout << a[idx].yy << ' ' << a[idx - 1].yy << ' ' << m << endl;
}
signed main()
{
    Ysanqian;
    int T;
    // T = 1;
    cin >> T;
    while (T--)
        solve();
}

G - Vlad and the Mountains(思维+离线+并查集)

题意:一条路径从a到b,总花费是 hb−ha ,hb-ha<=e才行,1: 对于hb>ha,那就是max(ℎa,ℎb)<=ha+e, 2: 对于hb<ha,那么max(ℎa,ℎb)==ha,一定小于ha+e,(其是就是为了维护第一种情况)所以这条路径能不能走只需要考虑这条路径上最大的 ℎi 即可。因此边(u,v)的边权只需看作是 max(ℎa,ℎb) ,所以如果起点为a,初始能量为e,那么只有边权max(ℎa,ℎb)小于等于 ℎa+e 的边在这次询问中能使用。

思路:话说也很巧我们几天训练赛刚刚做了一个离线+并查集的题,基本一样

询问 (a,b,e) 等价于只用边权 ≤ℎa+e 的边能否 联通a,b 节点,  离线, 将询问按 (ℎa+e) 值非降序排列,将边也是按max(hu , hv)非递减排序,这样就转化为了并查集可以维护的加边操做,对于每个询问,我们依次按排序后的边加入,这样就不要每询问一次就从头遍历一次边了,我们加入的边的max(hu, hv)一定是满足后面的要求的,所以对于后面的边如果可以加边就加边,不行的话就判断当前是否联通了

代码明天补。。。嘿嘿

写完检查了一晚上,早上有看了一个小时,最后才发现rode[ j ].w写成固定的w了,一直没更新(浪费太多时间了)

#include <bits/stdc++.h>
using namespace std;
#define pi acos(-1)
#define xx first
#define yy second
#define endl "\n"
#define int long long
#define pb push_back
typedef pair<int, int> PII;
#define max(a, b) (((a) > (b)) ? (a) : (b))
#define min(a, b) (((a) < (b)) ? (a) : (b))
#define Ysanqian ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
const int N = 1e6 + 10, M = 1010, inf = 0x3f3f3f3f, mod = 998244353;
int n, m, q;
int h[N];
int p[N];
int find(int x)
{
    if (x != p[x])
        p[x] = find(p[x]);
    return p[x];
}
struct node
{
    int u, v, w;
    bool operator<(const node &W) const
    {
        return w < W.w;
    }
} rode[N];
struct query
{
    int a, b, e, id, val;
    bool operator<(const query &A) const
    {
        return val < A.val;
    }
} query[N];
bool ans[N];
void solve()
{
    memset(ans, 0, sizeof ans);
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
        p[i] = i;
    for (int i = 1; i <= n; i++)
        cin >> h[i];
    for (int i = 1; i <= m; i++)
    {
        int u, v;
        cin >> u >> v;
        rode[i] = {u, v, max(h[u], h[v])};
    }
    sort(rode + 1, rode + 1 + m);
    cin >> q;
    for (int i = 1; i <= q; i++)
    {
        int a, b, e;
        cin >> a >> b >> e;
        query[i] = {a, b, e, i, h[a] + e};
    }
    sort(query + 1, query + q + 1);
    for (int i = 1, j = 1; i <= q; i++)
    {
        int a = query[i].a, b = query[i].b, id = query[i].id;
        int val = query[i].val;
        while (j <= m && rode[j].w <= val)
        {
            int x = find(rode[j].u), y = find(rode[j].v);
            p[x] = y;
            j++;
        }
        if (find(a) == find(b))
            ans[id] = 1;
        else
            ans[id] = 0;
    }
    for (int i = 1; i <= q; i++)
        if (ans[i])
            cout << "YES" << endl;
        else
            cout << "NO" << endl;
    cout << endl;
}
signed main()
{
    Ysanqian;
    int T;
    // T = 1;
    cin >> T;
    while (T--)
        solve();
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Codeforces Round 894 (Div. 3) 是一个Codeforces举办的比赛,是第894轮的Div. 3级别比赛。它包含了一系列题目,其中包括题目E. Kolya and Movie Theatre。 根据题目描述,E. Kolya and Movie Theatre问题要求我们给定两个字符串,通过三种操作来让字符串a等于字符串b。这三种操作分别为:交换a中相同位置的字符、交换a中对称位置的字符、交换b中对称位置的字符。我们需要先进行一次预处理,替换a中的字符,然后进行上述三种操作,最终得到a等于b的结果。我们需要计算预处理操作的次数。 根据引用的讨论,当且仅当b[i]==b[n-i-1]时,如果a[i]!=a[n-i-1],需要进行一次操作;否则不需要操作。所以我们可以遍历字符串b的前半部分,判断对应位置的字符是否与后半部分对称,并统计需要进行操作的次数。 以上就是Codeforces Round 894 (Div. 3)的简要说明和题目E. Kolya and Movie Theatre的要求。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [Codeforces Round #498 (Div. 3) (A+B+C+D+E+F)](https://blog.csdn.net/qq_46030630/article/details/108804114)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [Codeforces Round 894 (Div. 3)A~E题解](https://blog.csdn.net/gyeolhada/article/details/132491891)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值