代码在最后
[HNOI2013]比赛
记忆化搜索
把每一位还需要多少分用(27)进制压进(long) (long),(map)记忆化一下即可
[HNOI2013]消毒
先考虑在二维平面
问题就是最小点覆盖
最小点覆盖 = 二分图最大匹配
对于每个点((x,y)),(x)连向(y)一条边,然后跑最大匹配
扩展到三维
好像不太好搞....
(a*b*c<=5000)
我们把(a)调换成(min(a, b, c))
(a)最大为(sqrt[3]{5000})约(17)
对于每一层,要么和上面一起消,要么一次消掉这一层
枚举每层的状态
然后再跑最大匹配(O(2^{17}n^3))
[HNOI2013]旅行
构造+单调队列
题目大意:给定(1,-1)组成的序列,分成(m)段,使得(m)段绝对值最大值最小
设:
后缀和为(sum[i]),后缀和为(0)的个数为(cnt[i]),序列和为(S)
然后分类讨论
-
(S = 0)
(1.)若(cnt[1] ge m),则(ans = 0).直接选(0)的位置即可
维护一个单调队列
(2.) 若(cnt[1]<m), 则(ans = 1)
构造方法与 (S eq 0) 一样
-
(S eq 0)
(ans = lceilfrac{|S|}{m} ceil)
因为区间和为(0)的可以消掉,剩下的均分最小
现在问题是如何求出字典序最小的方案
假设上一个休息点已经确定为(last),当前决策到第(i)个休息点
那么新的休息点(第i个休息点)$$a$需要满足:
- (n - a ge m-i)
- (lceil frac{|sum[a + 1]|}{m - i} ceil leq ans)
- (|sum[last+1]-sum[a+1]| leq ans)
好像不太好搞,考虑暴力
我们可以对于每个每种(sum)开一个单调队列
每次暴力从([sum[last+1]-ans, sum[last+1]+ans]) 取出合法的放进答案队列
再维护答案队列的单调性,保证答案字典序最小
复杂度:(O(mlceil frac{|S|}{m} ceil) = O(|S|))
[HNOI2013]数列
(20\%):(dp)
(f[i][j])前(i)位,已经分了(j)份
转移用前缀和优化一下
(O(nk))
(100\%):
先写出式子:
设差分数组为:(a_1, a_2, a_3, ..., a_{k-1})
(sum^{m}_{a_1 = 1}sum^{m}_{a_2 = 1}sum^{m}_{a_3 = 1}...sum^{m}_{a_{k-1} = 1}(n-sum_{i=1}^{k-1}a_i))
(= n * m^{k-1} - sum^{m}_{a_1 = 1}sum^{m}_{a_2 = 1}sum^{m}_{a_3 = 1}...sum^{m}_{a_{k-1} = 1}sum_{i=1}^{k-1}a_i)
(=n*m^{k-1}-sum_{i=1}^{k-1}sum_{a_i=1}^m*m^{k-2})
(=n*m^{k-1}-(k-1)*m^{k-2}*frac{(m+1)m}{2})
(快速幂即可)
- 注意取模
[HNOI2013]游走
题面要求算边的期望
如果求出每条边期望经过次数,就可以求出答案
每条边经过次数,显然需要求出两端点期望经过次数
设点(i)期望次数为(f[i])
(deg[i])为(i)的入度
对于一个点(i)
存在边(x-i)
(f[i] = sum frac{f[x]}{deg[x]})
(f[1])要加(1),因为一开始在(1)
(f[n])不要算,因为到了(n)就停止
这个东西列个方程,高斯消元求
然后算出每条边经过次数的期望
对于(x-y)
(q[i] = f[x] / deg[x] + f[y] / deg[y])
显然经过次数多的边,赋值小
排序弄一下即可
[HNOI2013]切糕
最小割
题目其实就是求最小的代价使得每个纵轴被分成两部分
我们把每个点抽象成一条边,一个纵轴就是一条(S−T)的路径
但是题目要求(|f(x,y)−f(x′,y′)|≤D)
不能直接跑最小割
考虑如何限制
首先,(|f(x,y)−f(x′,y′)|≤D)是相互的
所以只要考虑 (f(x,y)−f(x′,y′)≤D)
那么对于((x, y, z)) 我们向它相邻列的第(x-D)层连一条(inf)边
贪心想一下,这样一定保证超过限制的两个点不会同时割掉
然后代码就很简单啦
Code
[HNOI2013]比赛
#include<bits/stdc++.h>
#define LL unsigned long long
#define RG register
using namespace std;
template<class T> inline void read(T &x) {
x = 0; RG char c = getchar(); bool f = 0;
while (c != '-' && (c < '0' || c > '9')) c = getchar(); if (c == '-') c = getchar(), f = 1;
while (c >= '0' && c <= '9') x = x*10+c-48, c = getchar();
x = f ? -x : x;
return ;
}
template<class T> inline void write(T x) {
if (!x) {putchar(48);return ;}
if (x < 0) x = -x, putchar('-');
int len = -1, z[20]; while (x > 0) z[++len] = x%10, x /= 10;
for (RG int i = len; i >= 0; i--) putchar(z[i]+48);return ;
}
const int N = 15, Mod = 1e9 + 7;
int n, s[N], ans, a[N], b[N], cnt1, cnt2;
map<LL, LL> M;
bool cmp(int x, int y) {
return x > y;
}
LL dfs(int x, int y) {
if (a[x] + (n - y + 1) * 3 < s[x]) return 0;
if (x == n) return 1;
if (y > n) {
for (int i = x + 1; i <= n; i++) b[i] = s[i] - a[i];
sort(b + 1 + x, b + n + 1, cmp);
LL S = n - x;
for (int i = x + 1; i <= n; i++) S = S * 27 + b[i];
if (M.find(S) != M.end()) return M[S];
else return M[S] = dfs(x + 1, x + 2);
}
LL res = 0;
if (a[x] + 3 <= s[x] && cnt1) {
a[x] += 3;
cnt1--;
(res += dfs(x, y + 1)) %= Mod;
a[x] -= 3;
cnt1++;
}
if (a[x] < s[x] && a[y] < s[y] && cnt2) {
a[x]++; a[y]++;
cnt2--;
(res += dfs(x, y + 1)) %= Mod;
a[x]--; a[y]--;
cnt2++;
}
if (a[y] + 3 <= s[y] && cnt1) {
a[y] += 3;
cnt1--;
(res += dfs(x, y + 1)) %= Mod;
a[y] -= 3;
cnt1++;
}
return res;
}
int main() {
read(n);
int sum;
for (int i = 1; i <= n; i++)
read(s[i]), sum += s[i];
sort(s+1, s+1+n, cmp);
cnt1 = sum - n * (n - 1);
cnt2 = (sum - cnt1 * 3) / 2;
printf("%lld
", dfs(1, 2));
return 0;
}
[HNOI2013]消毒
#include<bits/stdc++.h>
#define LL long long
#define RG register
using namespace std;
template<class T> inline void read(T &x) {
x = 0; RG char c = getchar(); bool f = 0;
while (c != '-' && (c < '0' || c > '9')) c = getchar(); if (c == '-') c = getchar(), f = 1;
while (c >= '0' && c <= '9') x = x*10+c-48, c = getchar();
x = f ? -x : x;
return ;
}
template<class T> inline void write(T x) {
if (!x) {putchar(48);return ;}
if (x < 0) x = -x, putchar('-');
int len = -1, z[20]; while (x > 0) z[++len] = x%10, x /= 10;
for (RG int i = len; i >= 0; i--) putchar(z[i]+48);return ;
}
const int N = 5010;
int a, b, c;
int q[3][N], ql, ans;
void init() {
ql = 0;
read(a), read(b), read(c);
int mn = min(a, min(b, c));
for (int i = 1; i <= a; i++)
for (int j = 1; j <= b; j++)
for (int k = 1; k <= c; k++) {
int x; read(x);
if (x == 1)
q[0][++ql] = i, q[1][ql] = j, q[2][ql] = k;
}
if (mn == b) {
swap(a, b); swap(q[0], q[1]);
}
else if (mn == c) {
swap(a, c); swap(q[0], q[2]);
}
return ;
}
bool flag[N], used[N];
int match[N];
struct node {
int to, nxt;
}g[N];
int last[N], gl;
void add(int x, int y) {
g[++gl] = (node) {y, last[x]};
last[x] = gl;
}
bool dfs(int u) {
for (int i = last[u]; i; i = g[i].nxt) {
int v = g[i].to;
if (used[v]) continue;
used[v] = 1;
if (!match[v] || dfs(match[v])) {
match[v] = u;
return 1;
}
}
return 0;
}
void work(int S) {
int res = 0;
for (int i = 0; i < a; i++)
if (S & (1 << i))
flag[i + 1] = 1, res++;
else flag[i + 1] = 0;
memset(last, 0, sizeof(last)); gl = 0;
memset(match, 0, sizeof(match));
for (int i = 1; i <= ql; i++)
if (!flag[q[0][i]])
add(q[1][i], q[2][i]);
for (int i = 1; i <= b; i++) {
for (int j = 1; j <= c; j++) used[j] = 0;
if (dfs(i)) res++;
}
ans = min(ans, res);
return ;
}
int main() {
int T;
read(T);
while (T--) {
init();
ans = 2147483647;
for (int i = 0; i < (1 << a); i++)
work(i);
printf("%d
", ans);
}
return 0;
}
[HNOI2013]旅行
#include<bits/stdc++.h>
#define LL long long
#define RG register
using namespace std;
template<class T> inline void read(T &x) {
x = 0; RG char c = getchar(); bool f = 0;
while (c != '-' && (c < '0' || c > '9')) c = getchar(); if (c == '-') c = getchar(), f = 1;
while (c >= '0' && c <= '9') x = x*10+c-48, c = getchar();
x = f ? -x : x;
return ;
}
template<class T> inline void write(T x) {
if (!x) {putchar(48);return ;}
if (x < 0) x = -x, putchar('-');
int len = -1, z[20]; while (x > 0) z[++len] = x%10, x /= 10;
for (RG int i = len; i >= 0; i--) putchar(z[i]+48);return ;
}
const int N = 5e5 + 5;
int n, m, a[N], sum[N], cnt[N];
struct Node { int l, r, v; } Line[N << 1]; int tot = 0;
struct deque {
int head, tail, len;
bool empty() { return !len; }
int newNode(int l, int r, int v) { Line[++tot] = (Node){ l, r, v }; return tot; }
int front() { return Line[head].v; }
int back() { return Line[tail].v; }
void pop_back() { tail = Line[tail].l, len--; }
void pop_front() { head = Line[head].r, len--; }
void push_back(int v) {
if (!len) head = tail = newNode(0, 0, v);
else Line[tail].r = newNode(tail, 0, v), tail = Line[tail].r;
len++;
}
void push(int v) {
while (len && a[back()] > a[v]) pop_back();
push_back(v);
}
} Q[N << 1], Qu[N << 1], *q = Q + N, *qu = Qu + N;
#define min(x, y) ((a[x]) < (a[y]) ? (x) : (y))
int main() {
read(n), read(m);
for (int i = 1; i <= n; i++)
read(a[i]), read(sum[i]), sum[i] = sum[i] ? 1 : -1;
for (int i = n - 1; i >= 1; i--) sum[i] += sum[i + 1];
for (int i = n; i >= 1; i--) cnt[i] = cnt[i + 1] + (!sum[i]);
int S = sum[1], d = S ? ceil(1.0 * abs(S) / m) : cnt[1] < m;
cnt[n + 1] = -1;
if (!d) {
for (int i = 1, j = 2; i < m; i++) {
while (cnt[j + 1] >= m - i) {
if (!sum[j + 1]) q[0].push(j);
j++;
}
printf("%d ", a[q[0].front()]);
q[0].pop_front();
}
}
else {
for (int i = 2; i <= n; i++) qu[sum[i]].push_back(i - 1);
int last = 0;
a[n + 1] = n + 1;
for (int i = 1; i < m; i++) {
int ans = n + 1;
for (int j = sum[last + 1] - d; j <= sum[last + 1] + d; j++) {
if (ceil(1.0 * abs(j) / (m - i)) > d) continue;
while (!qu[j].empty() && n - qu[j].front() >= m - i) {
if (qu[j].front() > last) q[j].push(qu[j].front());
qu[j].pop_front();
}
while (!q[j].empty() && q[j].front() <= last)
q[j].pop_front();
if (!q[j].empty()) ans = min(ans, q[j].front());
}
last = ans;
printf("%d ", a[ans]);
}
}
printf("%d
", a[n]);
return 0;
}
[HNOI2013]数列
#include<bits/stdc++.h>
#define LL long long
#define RG register
using namespace std;
template<class T> inline void read(T &x) {
x = 0; RG char c = getchar(); bool f = 0;
while (c != '-' && (c < '0' || c > '9')) c = getchar(); if (c == '-') c = getchar(), f = 1;
while (c >= '0' && c <= '9') x = x*10+c-48, c = getchar();
x = f ? -x : x;
return ;
}
template<class T> inline void write(T x) {
if (!x) {putchar(48);return ;}
if (x < 0) x = -x, putchar('-');
int len = -1, z[20]; while (x > 0) z[++len] = x%10, x /= 10;
for (RG int i = len; i >= 0; i--) putchar(z[i]+48);return ;
}
LL n, k, m, p;
LL fastpow(LL a, LL b) {
LL res = 1;
for (; b; b >>= 1, a = a * a % p) if (b & 1) res = res * a % p;
return res;
}
int main() {
//freopen(".in", "r", stdin);
//freopen(".out", "w", stdout);
read(n), read(k), read(m), read(p);
LL ans = (n % p * fastpow(m, k - 1) % p - (k - 1) * fastpow(m, k - 2) % p * ((m + 1) * m / 2 % p) % p + p) % p;
write(ans);
return 0;
}
[HNOI2013]游走
#include<bits/stdc++.h>
#define LL long long
#define RG register
using namespace std;
template<class T> inline void read(T &x) {
x = 0; RG char c = getchar(); bool f = 0;
while (c != '-' && (c < '0' || c > '9')) c = getchar(); if (c == '-') c = getchar(), f = 1;
while (c >= '0' && c <= '9') x = x*10+c-48, c = getchar();
x = f ? -x : x;
return ;
}
template<class T> inline void write(T x) {
if (!x) {putchar(48);return ;}
if (x < 0) x = -x, putchar('-');
int len = -1, z[20]; while (x > 0) z[++len] = x%10, x /= 10;
for (RG int i = len; i >= 0; i--) putchar(z[i]+48);return ;
}
const int N = 510;
struct node {
int to, nxt;
}g[N * 1000];
int last[N], gl, deg[N], n, m;
void add(int x, int y) {
g[++gl] = (node) {y, last[x]};
last[x] = gl;
g[++gl] = (node) {x, last[y]};
last[y] = gl;
deg[y]++; deg[x]++;
}
double a[N][N];
void Gauss() {
for (int i = 1, k; i < n; i++) {
k = i;
for (int j = i + 1; j < n; j++)
if (fabs(a[k][i]) < fabs(a[j][i])) k = j;
if (k != i) swap(a[k], a[i]);
for (int j = i + 1; j < n; j++)
for (int k = n; k >= i; k--)
a[j][k] -= a[i][k] * a[j][i] / a[i][i];
}
for (int i = n - 1; i; i--) {
for (int j = i + 1; j < n; j++)
a[i][n] -= a[i][j] * a[j][n];
a[i][n] /= a[i][i];
}
return ;
}
double q[N * N];
int X[N * N], Y[N * N];
int main() {
read(n); read(m);
for (int i = 1, x, y; i <= m; i++) {
read(x), read(y);
add(x, y);
X[i] = x, Y[i] = y;
}
for (int x = 1; x < n; x++) {
a[x][x] = 1;
for (int i = last[x]; i; i = g[i].nxt) {
int v = g[i].to;
if (v == n) continue;
a[x][v] = -1.0 / deg[v];
}
}
a[1][n] = 1;
Gauss();
for (int i = 1; i <= m; i++)
q[i] = a[X[i]][n] / deg[X[i]] + a[Y[i]][n] / deg[Y[i]];
sort(q + 1, q + 1 + m);
double ans = 0;
for (int i = 1; i <= m; i++)
ans += q[i] * (m - i + 1);
printf("%.3lf
", ans);
return 0;
}
[HNOI2013]切糕
#include<bits/stdc++.h>
#define LL long long
#define RG register
using namespace std;
template<class T> inline void read(T &x) {
x = 0; RG char c = getchar(); bool f = 0;
while (c != '-' && (c < '0' || c > '9')) c = getchar(); if (c == '-') c = getchar(), f = 1;
while (c >= '0' && c <= '9') x = x*10+c-48, c = getchar();
x = f ? -x : x;
return ;
}
template<class T> inline void write(T x) {
if (!x) {putchar(48);return ;}
if (x < 0) x = -x, putchar('-');
int len = -1, z[20]; while (x > 0) z[++len] = x%10, x /= 10;
for (RG int i = len; i >= 0; i--) putchar(z[i]+48);return ;
}
const int N = 80000, inf = 2147483647;
struct node {
int to, nxt, w;
}g[2000000];
int last[N], gl = 1;
void add(int x, int y, int z) {
g[++gl] = (node) {y, last[x], z};
last[x] = gl;
g[++gl] = (node) {x, last[y], 0};
last[y] = gl;
}
queue<int> q;
int dep[N], s, t, cur[N];
bool bfs() {
memset(dep, 0, sizeof(dep));
dep[s] = 1;
q.push(s);
while (!q.empty()) {
int u = q.front(); q.pop();
for (int i = last[u]; i; i = g[i].nxt) {
int v = g[i].to;
if (!dep[v] && g[i].w) {
dep[v] = dep[u]+1;
q.push(v);
}
}
}
return dep[t] == 0 ? 0 : 1;
}
int dfs(int u, int d) {
if (u == t) return d;
for (int &i = cur[u]; i; i = g[i].nxt) {
int v = g[i].to;
if (dep[v] == dep[u]+1 && g[i].w) {
int di = dfs(v, min(d, g[i].w));
if (di) {
g[i].w -= di;
g[i^1].w += di;
return di;
}
}
}
return 0;
}
int Dinic() {
int ans = 0;
while (bfs()) {
for (int i = 1; i <= t; i++) cur[i] = last[i];
while (int d = dfs(s, inf)) ans += d;
}
return ans;
}
int a[50][50][50], id[50][50][50];
int fx[] = {0, 1, -1, 0};
int fy[] = {1, 0, 0, -1};
int main() {
int p, q, r, d, tot = 0;
read(p), read(q), read(r), read(d);
for (int i = 1; i <= r; i++)
for (int j = 1; j <= p; j++)
for (int k = 1; k <= q; k++)
read(a[i][j][k]), id[i][j][k] = ++tot;
for (int j = 1; j <= p; j++)
for (int k = 1; k <= q; k++)
id[r+1][j][k] = ++tot;
s = tot+1, t = s+1;
for (int i = 1; i <= p; i++)
for (int j = 1; j <= q; j++)
add(s, id[1][i][j], inf), add(id[r+1][i][j], t, inf);
for (int k = 1; k <= r; k++)
for (int i = 1; i <= p; i++)
for (int j = 1; j <= q; j++)
add(id[k][i][j], id[k+1][i][j], a[k][i][j]);
for (int k = d+1; k <= r+1; k++)
for (int i = 1; i <= p; i++)
for (int j = 1; j <= q; j++) {
for (int z = 0; z < 4; z++) {
int x = i + fx[z], y = j + fy[z];
if (x < 1 || y < 1 || x > p || y > q) continue;
add(id[k][i][j], id[k-d][x][y], inf);
}
}
printf("%d
", Dinic());
return 0;
}