题面见 https://loj.ac/problems/tag/196,205
考虑每两个客人之间的时间间隔 Δ T i − 1 \Delta T_i - 1 ΔTi−1,这 n − 1 n-1 n−1 个关闭暖炉的机会中只能选择 n − k n - k n−k 个,故选择最大的 n − k n-k n−k 个。用 nth_element
即可 Θ ( n ) \Theta(n) Θ(n)。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#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;
}
按 A A A 排序,这样答案必然是选择其中一个连续区间,答案拆成有前缀和的形式 ( S r + A r ) − ( S l − 1 + A l ) (S_r + A_r) - (S_{l-1} + A_l) (Sr+Ar)−(Sl−1+Al),扫动的时候维护前缀最值。 Θ ( n log n ) \Theta(n\log n) Θ(nlogn)
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#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;
}
只需要关注哪些 G
字符之间有冲突,受团子的方向限制,它们必然只能是在一条斜线上的,对每条斜线上的 G G G 的选择进行 DP,设 f ( i , j ∈ { 0 , v e r t i c a l , h o r i z o n a l } ) f(i, j \in \{0, vertical, horizonal\}) f(i,j∈{0,vertical,horizonal}) 表示这个 G
串成的团子的方向。 Θ ( n m ) \Theta(nm) Θ(nm)
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#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;
}
预处理出 u , v u,v u,v 到每一个点的距离。在 s → t s\rightarrow t s→t 的最短路 DAG 上做一个 DP。还有一种情况是不借助月票,两种方案取较小值。主要就是跑 3 个单源最短路。 Θ ( m log m ) \Theta(m\log m) Θ(mlogm)
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#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;
}
将位分值成两部分,前 A A A 位和后 L − A L - A L−A 位。
对于询问中的前 A A A 位里的问号,枚举其可能的情况,对于后面的 L − A L - A L−A 位,处理出所有可能的询问的答案。
复杂度 Θ ( 2 A ( Q + 3 L − A ) ) \Theta(2^A(Q + 3^{L-A})) Θ(2A(Q+3L−A)),当 Q = 3 L − A Q = 3^{L-A} Q=3L−A 时,即取 A = L − log 3 Q A = L - \log_3Q A=L−log3Q 时复杂度约为 Θ ( Q 0.37 ⋅ 2 L ) \Theta(Q^{0.37} \cdot 2^L) Θ(Q0.37⋅2L)
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#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;
}