T1看错题,暴力没写对,爆0了,QWQ
A 灯
题目大意 : 有m种颜色的灯共n个,每次开启或关上一种颜色的所有,问有几个极长的连续段(注意极长,而不是最长)
- 对于灯数小于根号的颜色就暴力枚举每个点,对于灯数大于根号的颜色就记录下来,并预处理出这些颜色相互间的影响,而这些颜色种类是不超过根号的,复杂度 (O(nsqrt n))
Code
Show Code
#include <cmath>
#include <cstdio>
#include <vector>
using namespace std;
const int N = 1e5 + 5, M = 330;
int read(int x = 0, int f = 1, char c = getchar()) {
for (; c < '0' || c > '9'; c = getchar())
if (c == '-') f = -1;
for (; c >='0' && c <='9'; c = getchar())
x = x * 10 + c - '0';
return x * f;
}
bool l[N];
vector<int> v[N];
int n, m, q, sq, a[N], cnt[N], tot, id[N], f[M][M], ans, s[N], c[N];
int Cal(int x, int op) {
ans += cnt[x] * op;
if (id[x]) {
ans -= s[x] * op;
for (int i = 1; i <= tot; ++i)
if (l[c[i]]) ans -= f[id[x]][i] * op;
}
else {
for (int i = 0; i < v[x].size(); ++i) {
int y = v[x][i];
ans -= l[a[y-1]] * op; s[a[y-1]] += op;
ans -= l[a[y+1]] * op; s[a[y+1]] += op;
}
}
return ans;
}
int main() {
n = read(); m = read(); q = read();
for (int i = 1; i <= n; ++i)
if ((a[i] = read()) == a[i-1]) i--, n--;
a[n+1] = 0; sq = sqrt(n);
for (int i = 1; i <= n; ++i) cnt[a[i]]++;
for (int i = 1; i <= m; ++i)
if (cnt[i] > sq) c[++tot] = i, id[i] = tot;
for (int i = 1; i <= n; ++i) {
if (!id[a[i]]) v[a[i]].push_back(i);
f[id[a[i-1]]][id[a[i]]]++;
f[id[a[i]]][id[a[i-1]]]++;
}
while (q--) {
int x = read(); l[x] ^= 1;
printf("%d
", Cal(x, l[x] ? 1 : -1));
}
return 0;
}
B 十字路口
题目大意 : 给出一个红绿灯系统n个灯在m个时刻的状态,问红绿灯的周期
- 发现其实就是建图找环
Code
Show Code
#include <cstdio>
#include <vector>
#include <cstdlib>
#include <algorithm>
using namespace std;
const int N = 1e5 + 5;
int read(int x = 0, int f = 1, char c = getchar()) {
for (; c < '0' || c > '9'; c = getchar())
if (c == '-') f = -1;
for (; c >='0' && c <='9'; c = getchar())
x = x * 10 + c - '0';
return x * f;
}
struct Edge {
int n, t, d;
}e[N];
int h[N], edc;
void Add(int x, int y, int z) {
e[++edc] = (Edge) {h[x], y, z}; h[x] = edc;
}
bool v[N], g[N];
vector<int> f[N];
int n, m, a[N], i, j, d[N];
bool Cmp(int x, int y) {
return f[i][x] < f[i][y];
}
void Dfs(int x, int dis) {
d[x] = dis; v[x] = g[x] = 1;
for (int i = h[x], y; i; i = e[i].n) {
if (!v[y=e[i].t]) Dfs(y, dis + e[i].d);
else if (g[y]) {
printf("%d
", dis + e[i].d - d[y]);
exit(0);
}
}
g[x] = 0;
}
int main() {
m = read(); n = read();
for (i = 1; i <= n; ++i) {
f[i].resize(m + 1);
for (j = 1; j <= m; ++j)
f[i][j] = read();
}
for (i = 1; i <= m; ++i) a[i] = i;
for (i = 1; i <= n; ++i) {
sort(a + 1, a + m + 1, Cmp);
for (j = 2; j <= m; ++j) {
if (f[i][a[j]] == f[i][a[j-1]]) swap(a[j], a[j-1]);
else if (f[i][a[j-1]]) Add(a[j-1], a[j], f[i][a[j]] - f[i][a[j-1]]);
}
}
for (i = 1; i <= m; ++i) if (!v[i]) Dfs(i, 0);
puts("-1");
return 0;
}
C 密室逃脱
题目大意 : 一条通道里,想要通过需要有一定人数的人一直按着按钮,问保证1号点左面通道的门不会打开,通道里最多可以放多少个人
- 神仙Dp
Code
Show Code
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1005;
int read(int x = 0, int f = 1, char c = getchar()) {
for (; c < '0' || c > '9'; c = getchar())
if (c == '-') f = -1;
for (; c >='0' && c <='9'; c = getchar())
x = x * 10 + c - '0';
return x * f;
}
int n, m, a[N], b[N], f[N][N*20], ans;
//设 f[i][j]表示能到达第 i 个房间的人数恰好为 j 时, 前 i 个房间最多有多少人
int main() {
n = read(), m = read();
for (int i = 1; i < n; ++i)
a[i] = read(), b[i] = read();
memset(f, 0x8f, sizeof(f));
for (int i = 0; i < m; ++i) f[1][i] = i;
for (int i = 1; i < n; ++i) {
int mx = -2e9;
for (int j = 0; j < a[i]; ++j) {
mx = max(mx, f[i][j]);
f[i+1][j+b[i]] = max(f[i+1][j+b[i]], f[i][j] + b[i]);
}
for (int j = 0; j < b[i]; ++j)
f[i+1][j] = max(f[i+1][j], mx + j);
mx = a[i] + b[i];
for (int j = a[i]; j < mx; ++j)
f[i+1][j-a[i]] = max(f[i+1][j-a[i]], f[i][j]);
for (int j = mx; j <= 2e4; ++j)
f[i+1][j] = max(f[i+1][j], f[i][j]);
}
for (int i = 0; i <= 2e4; ++i)
ans = max(ans, f[n][i]);
printf("%d
", ans);
return 0;
}