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 ] 。从中选取两个数不能相等,和一个任意数x(x的值大于等于0,且
。求
的最大值。
思路:假设
。对于每一位来说(用m来说),若
,则
,若
,则
(m为二进制所在位数)。
因为如果 与
某一位不相同,那么这一位不论异或1还是0,最后都会得到一个1和一个0,然后相与为0,只有某一位相同才能通过改变x在该位的值使得这一位异或后等于1.
述就相当于 同或
后最大,那么也就是
异或
后最小。
然后有个结论,n个数的最小异或对答案就是排序后最小的相邻异或和。(这个是一位大佬赛后告诉的,本来想写字典树来着,结果发现不会。。)
可以提醒一下,会补字典树的
那我们就让他们不行等的位上的res为0好了,其实无所谓,就是图个方便
则。
#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();
}