B.Fire-Fighting Hero
题意:
有个着火点和
条联通的路保证整张图联通,现在有一个消防英雄和
支消防队伍,消防英雄要一个人从
点灭完所有的火,
支消防队伍可以合作灭完所有的火,比较消防英雄灭完最短路最大值点的距离除
和消防队伍灭完最短路最大值点的距离
题解:
题意比较难读懂,消防英雄的答案只需要以点作为起点跑一遍最短路即可,消防队伍可以合作,因此可以将这
个点都作为起点放入优先队列中跑一遍最短路
#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int> pii;
typedef long long ll;
const int VN = 1005;
const int EN = VN * VN / 2;
const int INF = 0x3f3f3f3f;
struct Edge
{
int v, next, w;
} E[EN];
priority_queue<pii, vector<pii>, greater<pii>> q;
int n, m, s, k, c, siz;
int head[VN];
int d[VN];
int u[EN], v[EN], w[EN], used[VN];
vector<int> V;
void init()
{
siz = 0;
memset(head, -1, sizeof(head));
while (!q.empty())
q.pop();
}
void addEdge(int u, int v, int w)
{
E[siz].v = v;
E[siz].w = w;
E[siz].next = head[u];
head[u] = siz++;
}
int Dijkstra()
{
for (int i = 1; i <= n; i++)
d[i] = INF, used[i] = 0;
for (int k : V)
d[k] = 0, q.push(pii(d[k], k));
while (!q.empty())
{
pii t = q.top();
q.pop();
int u = t.second;
if (d[u] < t.first || used[u])
continue;
used[u] = 1;
for (int e = head[u]; e != -1; e = E[e].next)
{
if (d[E[e].v] > d[u] + E[e].w)
{
d[E[e].v] = d[u] + E[e].w;
q.push(pii(d[E[e].v], E[e].v));
}
}
}
int maxans = 0;
for (int i = 1; i <= n; i++)
if (maxans < d[i])
maxans = d[i];
return maxans;
}
int main()
{
int t, m;
scanf("%d", &t);
while (t--)
{
init();
scanf("%d%d%d%d%d", &n, &m, &s, &k, &c);
V.clear();
for (int i = 1, x; i <= k; i++)
scanf("%d", &x), V.push_back(x);
for (int i = 0; i < m; i++)
{
scanf("%d%d%d", &u[i], &v[i], &w[i]);
addEdge(u[i], v[i], w[i]);
addEdge(v[i], u[i], w[i]);
}
int ans = Dijkstra();
V.clear();
V.push_back(s);
int t = Dijkstra();
if (t <= ans * c)
ans = t;
printf("%d\n", ans);
}
return 0;
} C.Hello 2019
题意:
给定一个长度为的序列和
次询问,询问
区间是否存在
的子序列,并且至少删除多少个字符使得不存在
的子序列
题解:
设置个状态。
表示初始状态,
表示只有
,
表示只有
,
表示只有
,
表示只有
这四个状态。用一个
的矩阵来进行状态转移,
表示从
状态到
状态的最小花费。因为考虑到区间维护,因此用线段树来维护
#include <bits/stdc++.h>
using namespace std;
const int maxn = 200020;
const int inf = 1e9;
struct node
{
int a[5][5];
node operator+(const node b) const
{
node c;
for (int i = 0; i < 5; i++)
for (int j = 0; j < 5; j++)
{
c.a[i][j] = inf;
for (int k = 0; k < 5; k++)
c.a[i][j] = min(c.a[i][j], a[i][k] + b.a[k][j]);
}
return c;
}
} e[maxn << 2];
char s[maxn];
int n, Q;
void build(int x, int l, int r)
{
if (l == r)
{
for (int i = 0; i < 5; i++)
for (int j = 0; j < 5; j++)
e[x].a[i][j] = (i == j) ? 0 : 1e9;
if (s[l] == '2')
{
e[x].a[0][0] = 1;
e[x].a[0][1] = 0;
}
else if (s[l] == '0')
{
e[x].a[1][1] = 1;
e[x].a[1][2] = 0;
}
else if (s[l] == '1')
{
e[x].a[2][2] = 1;
e[x].a[2][3] = 0;
}
else if (s[l] == '9')
{
e[x].a[3][3] = 1;
e[x].a[3][4] = 0;
}
else if (s[l] == '8')
{
e[x].a[3][3] = 1;
e[x].a[4][4] = 1;
}
return;
}
int mid = l + r >> 1;
build(x << 1, l, mid);
build(x << 1 | 1, mid + 1, r);
e[x] = e[x << 1] + e[x << 1 | 1];
}
node query(int x, int l, int r, int ql, int qr)
{
if (l == ql && r == qr)
return e[x];
int mid = l + r >> 1;
if (qr <= mid)
return query(x << 1, l, mid, ql, qr);
if (ql > mid)
return query(x << 1 | 1, mid + 1, r, ql, qr);
return query(x << 1, l, mid, ql, mid) + query(x << 1 | 1, mid + 1, r, mid + 1, qr);
}
int main()
{
scanf("%d%d%s", &n, &Q, s + 1);
reverse(s + 1, s + n + 1);
build(1, 1, n);
while (Q--)
{
int l, r;
scanf("%d%d", &l, &r);
l = n - l + 1, r = n - r + 1;
swap(l, r);
int ans = query(1, 1, n, l, r).a[0][4];
if (ans == inf)
printf("-1\n");
else
printf("%d\n", ans);
}
} E.Magic Master
题意:
给定张牌和一个数
,每次操作将最上面的牌取出,再进行
次把最上面的牌放到最下面,直至所以牌都被取出,要使得所有被取出的牌恰好满足
,询问一开始牌的摆放顺序
题解:
这题的难点在于读题,首先可以明确第一次取出的牌肯定是,因此
肯定摆在首位,再明确最后一次肯定只剩下
号牌,那么不妨倒序遍历,每次都把第
张牌放入头部,再把最后的
张牌依次放到头部,因为第一次固定取
,所以后面顺序就变成了先排
张牌,再取一张牌,这样操作就能保证第
张号肯定在第
次被取到。这个操作可以用双端队列来实现,模拟即可
#include<bits/stdc++.h>
using namespace std;
int main()
{
int t;
scanf("%d", &t);
while (t--)
{
deque<int> s;
int n, m;
scanf("%d%d", &n, &m);
s.push_front(n);
for (int i = n - 1; i > 1; i--)
{
s.push_front(i);
for (int j = 1; j <= m; j++)
{
int tmp = s.back();
s.pop_back();
s.push_front(tmp);
}
}
s.push_front(1);
int q, x;
scanf("%d", &q);
while (q--)
{
scanf("%d", &x);
printf("%d\n", s[x - 1]);
}
}
return 0;
} G.Pangu Separates Heaven and Earth
题意:
输入为时输出
,否则输出
题解:
签到题
#include <stdio.h>
int main()
{
int t;
scanf("%d", &t);
while (t--)
{
int n;
scanf("%d", &n);
if (n == 1)
printf("18000\n");
else
printf("0\n");
}
} H.The Nth Item
题意:
给定一个序列。
次询问每次询问第
项对
取模的值。
题解:
猜想存在循环节,因此可以用map记忆化搜索把答案存储下来,每次结果取
的左上角值即为答案。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int p = 998244353;
struct Matrix
{
int t;
ll a[3][3];
Matrix(int t0) : t(t0)
{ // 初始化成t阶单位矩阵
memset(a, 0, sizeof(a));
for (int i = 0; i < t; i++)
a[i][i] = 1;
}
Matrix operator*(const Matrix &y);
void Output();
};
Matrix Matrix::operator*(const Matrix &y)
{ // 矩阵乘法的运算符重载
Matrix r(t);
for (int i = 0; i < t; i++)
for (int j = 0; j < t; j++)
{
r.a[i][j] = 0;
for (int k = 0; k < t; k++)
r.a[i][j] += a[i][k] * y.a[k][j];
r.a[i][j] %= p;
}
return r;
}
Matrix ksm(Matrix A, ll n)
{
Matrix B(2), M(2);
B = Matrix(2);
M = A; // 保存A的2整数次幂的幂
while (n)
{
if (n & 1)
B = B * M;
n >>= 1;
M = M * M;
}
return B;
}
map<ll, ll> mp;
int main()
{
ll q, n;
scanf("%lld%lld", &q, &n);
Matrix A(2);
A.a[0][0] = 3;
A.a[0][1] = 2;
A.a[1][0] = 1;
A.a[1][1] = 0;
ll ans = 0, tmp;
Matrix res(2);
for (int i = 1; i <= q; i++)
{
if (mp[n] == 0)
{
res = ksm(A, n - 1ll);
tmp = res.a[0][0];
mp[n] = tmp;
}
else
res.a[0][0] = mp[n];
n = n ^ (tmp * tmp);
ans ^= tmp;
}
printf("%lld\n", ans);
return 0;
} I.Yukino With Subinterval
题意:
给定一个长度为的序列
,有两种操作:
:将
的值改为
:询问区间
有多少个最长相等字串,且值在
之间
题解:
把所有连续段缩到它的左端点,查询的时候只要查区间内有多少个左端点即可。但是考虑到
可能也属于一个最长相等字串内,因此要特判一下
是否等于
。查询左端点数用主席树即可实现,考虑到修改,可以用树状数组来维护主席树,因此就是树状数组套主席树
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5 + 10;
int n, m, a[N];
inline int lowbit(int x) { return x & -x; }
struct PST
{
int sum[N * 200], ls[N * 200], rs[N * 200];
int rt[N], tot, maxn;
void update_SgT(int &rt, int l, int r, int pos, int val)
{
if (!rt)
rt = ++tot;
sum[rt] += val;
if (l == r)
return;
int mid = l + r >> 1;
if (pos <= mid)
update_SgT(ls[rt], l, mid, pos, val);
else
update_SgT(rs[rt], mid + 1, r, pos, val);
}
void update_BIT(int x, int pos, int v)
{
for (; x <= maxn; x += lowbit(x))
update_SgT(rt[x], 1, n, pos, v);
}
int rt1[30][30], rt2[30][30], cnt1, cnt2;
void locate(int l, int r)
{
cnt1 = cnt2 = 0;
for (int i = l - 1; i; i -= lowbit(i))
rt1[++cnt1][0] = rt[i];
for (int i = r; i; i -= lowbit(i))
rt2[++cnt2][0] = rt[i];
}
int query(int dep, int l, int r, int ql, int qr)
{
if (ql > qr)
return 0;
int res = 0;
if (l >= ql && r <= qr)
{
for (int i = 1; i <= cnt1; i++)
res -= sum[rt1[i][dep]];
for (int i = 1; i <= cnt2; i++)
res += sum[rt2[i][dep]];
return res;
}
int mid = l + r >> 1;
if (ql <= mid)
{
for (int i = 1; i <= cnt1; i++)
rt1[i][dep + 1] = ls[rt1[i][dep]];
for (int i = 1; i <= cnt2; i++)
rt2[i][dep + 1] = ls[rt2[i][dep]];
res += query(dep + 1, l, mid, ql, qr);
}
if (qr > mid)
{
for (int i = 1; i <= cnt1; i++)
rt1[i][dep + 1] = rs[rt1[i][dep]];
for (int i = 1; i <= cnt2; i++)
rt2[i][dep + 1] = rs[rt2[i][dep]];
res += query(dep + 1, mid + 1, r, ql, qr);
}
return res;
}
} PST;
int main()
{
scanf("%d%d", &n, &m);
PST.maxn = n;
for (int i = 1; i <= n; i++)
{
scanf("%d", &a[i]);
if (a[i] != a[i - 1])
PST.update_BIT(i, a[i], 1);
}
while (m--)
{
int op, l, r, x, y;
scanf("%d%d%d", &op, &l, &r);
if (op == 1)
{
if (a[l] == r)
continue;
if (a[l] != a[l - 1])
PST.update_BIT(l, a[l], -1);
if (a[l] == a[l + 1])
PST.update_BIT(l + 1, a[l + 1], 1);
else if (r == a[l + 1])
PST.update_BIT(l + 1, a[l + 1], -1);
a[l] = r;
if (a[l] != a[l - 1])
PST.update_BIT(l, a[l], 1);
}
else
{
scanf("%d%d", &x, &y);
PST.locate(l, r);
int ans = PST.query(0, 1, n, x, y);
if (a[l] == a[l - 1] && a[l] >= x && a[l] <= y)
ans++;
printf("%d\n", ans);
}
}
return 0;
} 
京公网安备 11010502036488号