@2368860385
2018-12-20T11:19:06.000000Z
字数 6101
阅读 206
比赛总结
预计:100+100+0
实际:100+100+0
第三题最后1分钟交的,一交就测了(按提交时间逆序评测),不用预计了,直接返回了成绩。
T1
感觉比较可做,写了三个小时,有点慢了,最后由于一个bug调了很长时间,和暴力拍上就交了(一直担心暴力也是错的。。)
T2
读完题感觉是树形背包,写完T1,写了半小时,过了样例,就交了。试了几组小样例,发现了一个bug!!!,然后改,改完过了就交了;又试了一组小样例,又发现一个bug,改过又交了;又试了一组小样例,又发现一个bug,改过又叫了....(重复几次);由于不知道怎么拍,只能靠造几组小样例检验,最后又改了几个地方,使代码更安全,就交了。
幸亏多试了几组,前面的交的全0分。。
T3
写完前两道,看的第三道,(T1花了3个小时,T2半小时,此时还有半小时),读完好像是网络流,感觉不能这么简单吧。。仔细想了会,好像就是网络流。好像有点不敢写(想到noip day1 T3),不过这次还好,坚信,就是简单题!
于是就写了,不过时间紧,思绪混乱,没调出。
混乱到什么程度?开始想二分最大值,写着写着忘了。用费用流判断是否满流。。
总结:
时间分配,T1花的时间有点长。
T3比较好,这次敢写了,其实就是网络流。
n^3:枚举一条水平线,枚举一个高度,计算以这个高度,底是这条线的矩形的贡献。居然可以有70分。
n^2:枚举一条水平线,计算所有以这条水平线为底的矩形的贡献。
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cmath>
#include<cctype>
#include<set>
#include<map>
#include<queue>
#include<vector>
using namespace std;
typedef long long LL;
inline int read() {
int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
}
const int N = 2005;
LL tot[N][N], sum2[N], h[N][N], sumh[N][N];
char s[N][N];
inline LL Calc(LL m) { // xigema i=0 to m i * (n - i + 1)
return m * (m + 1) / 2 * m - sum2[m] + (m * (m + 1)) / 2;
}
void init(int n,int m) {
int mx = max(n, m);
for (int i = 1; i <= mx; ++i) sum2[i] = sum2[i - 1] + i * i;
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j)
tot[i][j] = Calc(i) * Calc(j), h[i][j] = Calc(j) * i;
for (int j = 1; j <= m; ++j)
for (int i = 1; i <= n; ++i)
sumh[i][j] += sumh[i - 1][j] + h[i][j];
}
/*
namespace BF1{
int sum[N][N];
// int tmp[N];
void solve2(int n,int m) {
LL Ans = 0;
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j)
sum[i][j] = sum[i - 1][j] + (s[i][j] == '#');
for (int i = 1; i <= n; ++i) {
for (int j = i; j <= n; ++j) {
int last = 0;
for (int k = 1; k <= m; ++k)
if (sum[j][k] - sum[i - 1][k])
// Ans += h[j - i + 1][k - 1 - last], last = k;
// tmp[j] += 1ll * Calc(k - 1 - last) * (j - i + 1),
Ans += 1ll * Calc(k - 1 - last) * (j - i + 1), last = k;
// if (last != m) Ans += h[j - i + 1][m - last];
if (last != m) Ans += 1ll * Calc(m - last) * (j - i + 1);
// tmp[j] += 1ll * Calc(m - last) * (j - i + 1);
}
}
// for (int i = 1; i <= n; ++i) cout << tmp[i] << " "; puts("");
cout << Ans;
}
}
*/
int sk[N], u[N][N];
inline LL Calc2(int i,int j,int x,int y) {
if (x == y) return 0;
return sumh[y][j - i] - sumh[x][j - i];
}
void solve(int n,int m) {
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j)
u[i][j] = (s[i][j] == '.' ? u[i - 1][j] + 1 : 0);
LL Ans = 0;
for (int top, i = 1; i <= n; ++i) {
// LL tmp = 0;
top = 0; sk[++top] = 0;
for (int j = 1; j <= m; ++j) {
while (top && u[i][j] < u[i][sk[top]]) {
Ans += Calc2(sk[top - 1], j - 1, max(u[i][j], u[i][sk[top - 1]]), u[i][sk[top]]);
// tmp += Calc2(sk[top - 1], j - 1, max(u[i][j], u[i][sk[top - 1]]), u[i][sk[top]]);
top --;
}
while (top && u[i][j] == u[i][sk[top]]) top--;
sk[++top] = j;
}
while (top >= 2) {
// tmp += Calc2(sk[top - 1], m, u[i][sk[top - 1]], u[i][sk[top]]);
Ans += Calc2(sk[top - 1], m, u[i][sk[top - 1]], u[i][sk[top]]); top --;
// Ans += Calc2(sk[top - 1], sk[top], u[i][sk[top - 1]], u[i][sk[top]]);top --;
}
// cout << tmp << " ";
}
// puts("");
cout << Ans;
}
int main() {
// freopen("1.txt", "r", stdin);
int n = read(), m = read();
for (int i = 1; i <= n; ++i) scanf("%s", s[i] + 1);
init(n, m);
// if (n <= 300 && m <= 300) { BF1::solve2(n, m); return 0; }
solve(n, m);
return 0;
}
/*
4 5
#.##.
.#...
#.#..
..#..
5 6
..#..#
#.####
#.#.##
.##..#
##.###
*/
树形dp,有一种情况是进去又不回来了,还有进去后回来。分别转移。
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cmath>
#include<cctype>
#include<set>
#include<map>
#include<queue>
#include<vector>
using namespace std;
typedef long long LL;
inline int read() {
int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
}
const int N = 505;
int f[N][N][2], w[N], siz[N];
vector<int> T[N];
int n, m;
void dfs(int u,int fa) {
f[u][1][0] = f[u][1][1] = w[u]; siz[u] = 1;
for (int sz = T[u].size(), i = 0; i < sz; ++i) {
int v = T[u][i];
if (v == fa) continue;
dfs(v, u);
siz[u] += siz[v];
for (int j = min(siz[u] * 3, m); j >= 1; --j) {
for (int k = 0, lim = min(j, min(siz[v] * 3, m)); k <= lim; ++k) {
if (j - k - 1 >= 0) f[u][j][0] = max(f[u][j][0], f[v][k][0] + f[u][j - k - 1][1]);
if (j - k - 2 >= 0) f[u][j][0] = max(f[u][j][0], f[v][k][1] + f[u][j - k - 2][0]);
if (j - k - 2 >= 0) f[u][j][1] = max(f[u][j][1], f[v][k][1] + f[u][j - k - 2][1]);
}
}
}
}
int main() {
// freopen("1.txt", "r", stdin);
n = read(), m = read();
for (int i = 1; i <= n; ++i) w[i] = read();
for (int i = 1; i < n; ++i) {
int u =read(),v = read(); T[u].push_back(v); T[v].push_back(u);
}
dfs(1, 0);
int ans = 0;
for (int i = 0; i <= m; ++i) ans = max(ans, max(f[1][i][0], f[1][i][1]));
cout << ans;
return 0;
}
/*
2 1
8 9
1 2
2 2
8 9
1 2
2 3
8 9
1 2
3 5
9 2 5
1 2
1 3
5 8
3 2 3 4 1
1 2
1 3
2 4
2 5
*/
二分最大值,建图,网络流判断是否满流。
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cmath>
#include<cctype>
#include<set>
#include<map>
#include<queue>
#include<vector>
using namespace std;
typedef long long LL;
inline int read() {
int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
}
const int N = 105 * 5;
struct Edge{
int to, nxt, c;
Edge() {}
Edge(int x,int y,int z) { to = x, nxt = y, c = z; }
}e[1000005];
struct Node{
int x, y;
}A[N], B[N];
int head[N], q[N], dis[N], D[N][N], cur[N];
vector<int> C[N];
int En = 1, S, T, n, m, c, k;
inline void add_edge(int u,int v,int w) {
++En; e[En] = Edge(v, head[u], w); head[u] = En;
++En; e[En] = Edge(u, head[v], 0); head[v] = En;
}
inline int sqr(int x) { return x * x; }
inline int dist(const Node &A,const Node &B) { return sqr(A.x - B.x) + sqr(A.y - B.y); }
bool bfs() {
for (int i = 0; i <= T; ++i) dis[i] = -1, cur[i] = head[i];
int L = 1, R = 0; q[++R] = S, dis[S] = 0;
while (L <= R) {
int u = q[L ++];
for (int i = head[u]; i; i = e[i].nxt) {
int v = e[i].to;
if (dis[v] == -1 && e[i].c > 0) {
dis[v] = dis[u] + 1; q[++R] = v;
if (v == T) return 1;
}
}
}
return 0;
}
int dfs(int u,int flow) {
if (u == T) return flow;
int used = 0;
for (int &i = cur[u]; i; i = e[i].nxt) {
int v = e[i].to;
if (dis[v] == dis[u] + 1 && e[i].c > 0) {
int t = dfs(v, min(flow - used, e[i].c));
if (t > 0) {
e[i].c -= t, e[i ^ 1].c += t;
used += t;
if (used == flow) break;
}
}
}
if (flow != used) dis[u] = -1;
return used;
}
int Dinic() {
int ans = 0;
while (bfs()) ans += dfs(S, 1e9);
return ans;
}
bool check(int x) {
En = 1;
for (int i = 0; i <= T; ++i) head[i] = 0; // T!!! not n
for (int i = 1; i <= n; ++i) add_edge(S, i, 1);
for (int i = 1; i<= n; ++i)
for (int j = 1; j <= m; ++j)
if (D[i][j] <= x) add_edge(i, j + n, 1);
for (int i = 1; i <=k; ++i)
for (int sz = C[i].size(), j = 0; j < sz; ++j)
add_edge(C[i][j] + n, i + n + m, 1e9);
for (int i = 1; i <= k; ++i) add_edge(i + n + m, T, c);
return Dinic() == n;
}
int main() {
n = read(), m =read(), c = read(), k = read();
for (int i = 1; i <= n; ++i) A[i].x = read(), A[i].y = read();
for (int i = 1; i <= m; ++i) B[i].x = read(), B[i].y = read();
for (int i = 1; i <= k; ++i)
for (int T = read(); T--; ) C[i].push_back(read());
S = 0, T = n + m + k + 1; // T = n + n + k !!!
int L = 0, R = 0, ans = 0;
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j)
R = max(R, D[i][j] = dist(A[i], B[j]));
while (L <= R) {
int mid = (L + R) >> 1;
if (check(mid)) ans = mid, R = mid - 1;
else L = mid + 1;
}
cout << ans;
return 0;
}