版权声明:本文为博主原创文章,在标注作者的情况下可自由转载。 https://blog.csdn.net/EI_Captain/article/details/87879815
题面见 https://loj.ac/problems/tag/196,205
T1 寒冬暖炉
考虑每两个客人之间的时间间隔
,这
个关闭暖炉的机会中只能选择
个,故选择最大的
个。用 nth_element
即可
。
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <ctime>
#include <cctype>
#include <algorithm>
#include <functional>
#include <set>
#include <map>
#include <vector>
#include <iostream>
#include <limits>
#include <numeric>
#define LOG(FMT...) fprintf(stderr, FMT)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int N = 100010;
int n, k;
int t[N], a[N];
int main() {
#ifndef ONLINE_JUDGE
freopen("test.in", "r", stdin);
int nol_cl = clock();
#endif
scanf("%d%d", &n, &k);
for (int i = 1; i <= n; ++i)
scanf("%d", &t[i]);
int ans = t[n] - t[1] + 1;
for (int i = 1; i < n; ++i)
a[i] = t[i + 1] - t[i] - 1;
nth_element(a + 1, a + k, a + n, greater<int>());
ans -= accumulate(a + 1, a + k, 0);
printf("%d\n", ans);
#ifndef ONLINE_JUDGE
LOG("Time: %dms\n", int ((clock()
-nol_cl) / (double)CLOCKS_PER_SEC * 1000));
#endif
return 0;
}
T2
按 排序,这样答案必然是选择其中一个连续区间,答案拆成有前缀和的形式 ,扫动的时候维护前缀最值。
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <ctime>
#include <cctype>
#include <algorithm>
#include <functional>
#include <set>
#include <map>
#include <vector>
#include <iostream>
#include <limits>
#include <numeric>
#define LOG(FMT...) fprintf(stderr, FMT)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int N = 500010;
int n;
pair<ll, int> art[N];
int main() {
#ifndef ONLINE_JUDGE
freopen("test.in", "r", stdin);
int nol_cl = clock();
#endif
scanf("%d", &n);
for (int i = 1; i <= n; ++i)
scanf("%lld%d", &art[i].first, &art[i].second);
sort(art + 1, art + n + 1);
ll ans = 0, pre = -1LL << 60, s = 0;
for (int i = 1; i <= n; ++i) {
pre = max(pre, -s + art[i].first);
s += art[i].second;
ans = max(ans, pre + s - art[i].first);
}
printf("%lld\n", ans);
#ifndef ONLINE_JUDGE
LOG("Time: %dms\n", int ((clock()
-nol_cl) / (double)CLOCKS_PER_SEC * 1000));
#endif
return 0;
}
T3 团子制作
只需要关注哪些 G
字符之间有冲突,受团子的方向限制,它们必然只能是在一条斜线上的,对每条斜线上的
的选择进行 DP,设
表示这个 G
串成的团子的方向。
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <ctime>
#include <cctype>
#include <algorithm>
#include <functional>
#include <set>
#include <map>
#include <vector>
#include <iostream>
#include <limits>
#include <numeric>
#define LOG(FMT...) fprintf(stderr, FMT)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int N = 3010;
int n, m, ans, cnt;
char s[N][N];
bool ab[N][2];
int dp[N][3];
void prog() {
for (int i = 1; i <= cnt + 1; ++i) {
dp[i][2] = *max_element(dp[i - 1], dp[i - 1] + 3);
dp[i][0] = ab[i][0] ? (max(dp[i - 1][0], dp[i - 1][2]) + 1) : 0;
dp[i][1] = ab[i][1] ? (max(dp[i - 1][1], dp[i - 1][2]) + 1) : 0;
}
ans += dp[cnt + 1][2];
}
int main() {
#ifndef ONLINE_JUDGE
freopen("test.in", "r", stdin);
int nol_cl = clock();
#endif
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; ++i)
scanf("%s", s[i] + 1);
for (int k = 2; k <= n + m; ++k) {
for (int i = 1; i <= n; ++i) {
int j = k - i;
if (j < 1 || j > m)
continue;
if (s[i][j] != 'G') {
if (cnt)
prog();
cnt = 0;
} else {
++cnt;
ab[cnt][0] = s[i - 1][j] == 'R' && s[i + 1][j] == 'W';
ab[cnt][1] = s[i][j - 1] == 'R' && s[i][j + 1] == 'W';
}
}
if (cnt)
prog();
cnt = 0;
}
printf("%d\n", ans);
#ifndef ONLINE_JUDGE
LOG("Time: %dms\n", int ((clock()
-nol_cl) / (double)CLOCKS_PER_SEC * 1000));
#endif
return 0;
}
T4 月票购买
预处理出 到每一个点的距离。在 的最短路 DAG 上做一个 DP。还有一种情况是不借助月票,两种方案取较小值。主要就是跑 3 个单源最短路。
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <ctime>
#include <cctype>
#include <algorithm>
#include <functional>
#include <queue>
#include <set>
#include <map>
#include <vector>
#include <iostream>
#include <limits>
#include <numeric>
#define LOG(FMT...) fprintf(stderr, FMT)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
struct Node {
int u;
ll step;
Node(int u, ll step) : u(u), step(step) {}
bool operator>(const Node &rhs) const {
return step > rhs.step;
}
};
struct Edge {
int v, w;
Edge* next;
};
const int N = 100010, M = 200010;
int n, m;
int s, t, a, b;
ll ans;
Edge* g[N];
bool vis[N];
ll diss[N], disa[N], disb[N], da[N], db[N];
void adde(int u, int v, int w);
void runspt(int s, ll* dis);
void dfs(int u);
int main() {
#ifndef ONLINE_JUDGE
freopen("test.in", "r", stdin);
int nol_cl = clock();
#endif
scanf("%d%d%d%d%d%d", &n, &m, &s, &t, &a, &b);
while (m--) {
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
adde(u, v, w);
adde(v, u, w);
}
runspt(a, disa);
ans = disa[b];
if (disa[s] != -1) {
runspt(b, disb);
runspt(s, diss);
dfs(t);
}
printf("%lld\n", ans);
#ifndef ONLINE_JUDGE
LOG("Time: %dms\n", int ((clock()
-nol_cl) / (double)CLOCKS_PER_SEC * 1000));
#endif
return 0;
}
void dfs(int u) {
if (vis[u])
return;
vis[u] = true;
da[u] = disa[u];
db[u] = disb[u];
for (Edge* p = g[u]; p; p = p->next)
if (diss[p->v] + p->w == diss[u]) {
dfs(p->v);
da[u] = min(da[u], da[p->v]);
db[u] = min(db[u], db[p->v]);
}
ans = min(ans, min(da[u] + disb[u], db[u] + disa[u]));
}
void runspt(int s, ll* dis) {
memset(dis, -1, sizeof(ll) * (n + 1));
priority_queue<Node, vector<Node>, greater<Node>> q;
q.emplace(s, dis[s] = 0);
while (!q.empty()) {
Node tmp = q.top();
q.pop();
if (tmp.step != dis[tmp.u])
continue;
for (Edge* p = g[tmp.u]; p; p = p->next)
if (dis[p->v] == -1 || dis[p->v] > tmp.step + p->w)
q.emplace(p->v, dis[p->v] = tmp.step + p->w);
}
}
void adde(int u, int v, int w) {
static Edge pool[M * 2];
static Edge* p = pool;
p->v = v;
p->w = w;
p->next = g[u];
g[u] = p;
++p;
}
T5 毒蛇越狱
将位分值成两部分,前
位和后
位。
对于询问中的前
位里的问号,枚举其可能的情况,对于后面的
位,处理出所有可能的询问的答案。
复杂度
,当
时,即取
时复杂度约为
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <ctime>
#include <cctype>
#include <algorithm>
#include <functional>
#include <set>
#include <map>
#include <vector>
#include <iostream>
#include <limits>
#include <numeric>
#define LOG(FMT...) fprintf(stderr, FMT)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
struct IO_Tp
{
const static int _O_Buffer_Size = 10 << 20;
char _O_Buffer[_O_Buffer_Size], *_O_pos = _O_Buffer;
IO_Tp()
{
}
~IO_Tp()
{
fwrite(_O_Buffer, 1, _O_pos - _O_Buffer, stdout);
}
IO_Tp &operator<<(int n)
{
static char _buf[10];
char* _pos = _buf;
do
*_pos++ = '0' + n % 10;
while (n /= 10);
while (_pos != _buf)
*_O_pos++ = *--_pos;
return *this;
}
IO_Tp &operator<<(char ch)
{
*_O_pos++ = ch;
return *this;
}
} IO;
const int N = 1000010, L = 20;
int l, n;
char v[(1 << L) + 10];
char tmp[L + 4];
unsigned short sum[1 << 12][1 << 12];
int ind[N], cc[N];
int ans[N];
int main() {
#ifndef ONLINE_JUDGE
freopen("test.in", "r", stdin);
int nol_cl = clock();
#endif
scanf("%d%d%s", &l, &n, v);
for (int i = 1; i <= n; ++i) {
scanf("%s", tmp + 1);
for (int j = 0; j < l; ++j)
if (tmp[l - j] == '?')
cc[i] |= 1 << j;
else
ind[i] |= (tmp[l - j] - '0') << j;
}
int a = max(0, l - int(log(n) / log(3))), b = l - a;
if (a > 12) {
a = 12;
b = l - a;
} else if (b > 12) {
b = 12;
a = l - b;
}
for (int i = 0; i != (1 << l); ++i)
v[i] -= '0';
for (int pre = 0; pre != 1 << a; ++pre) {
for (int s = 0; s != 1 << b; ++s)
sum[0][s] = v[pre | s << a];
for (int cov = 1; cov != 1 << b; ++cov) {
int tr = __builtin_ctz(cov);
int ccov = ~cov & ((1 << b) - 1);
for (int s = ccov; ; s = (s - 1) & ccov) {
sum[cov][s] = sum[cov ^ 1 << tr][s] + sum[cov ^ 1 << tr][s | 1 << tr];
if (!s)
break;
}
}
for (int i = 1; i <= n; ++i)
if ((~cc[i] & pre) == (ind[i] & ((1 << a) - 1)))
ans[i] += sum[cc[i] >> a][ind[i] >> a];
for (int cov = 0; cov != 1 << b; ++cov)
for (int s = cov; ; s = (s - 1) & cov) {
sum[~cov & ((1 << b) - 1)][s & cov] = 0;
if (!s)
break;
}
}
for (int i = 1; i <= n; ++i)
IO << ans[i] << '\n';
#ifndef ONLINE_JUDGE
LOG("Time: %dms\n", int ((clock()
-nol_cl) / (double)CLOCKS_PER_SEC * 1000));
#endif
return 0;
}