游记
Day 1
前天晚上两点睡的,宾馆隔壁就是ktv,感觉自己萌萌哒。
开考
到了考场写完对拍就弃疗了,拿到试题就开始看,关屏幕先看上半小时题再说。
第一题数论,看十分钟把30分写纸上就弃疗了。
一开始第二题读错题了,看成了可以随便染色,然后就喜闻乐见的弃疗了(事实证明真是一个英明的决定)。
第三题卧槽裸矩阵。。。和TJOI棋盘那道题几乎一样。。。然后在纸上打了打草就觉得没问题。
好了策略决定,T3(0分dfs) -> T3(20分dp)->拍->T3(100分矩阵)
码码码。。。
2h
刚t1吧(是不是欧拉函数?)
关了屏幕推推推。。。
弃疗
4h
写t2吧
重新读题 发现好像树剖有部分分 先写个暴力再说(然而我写了假的暴力)
码码码。。。
4.8h
写完了,ce了
检查文件名+检查变量
最后t3被卡掉一个点,30+0+90=120
Day 2
前天晚上十点睡的,不要在意为什么我对睡觉这么执着。。。
开考
拿到试题,第一题01分数规划,第二题ac自动机上的dp(傻逼选手以为有100分),第三题哎哎哎我好像做过一个维护方差的线段树,不就是合并合并剩下
∑(x[i])
,
∑(x[i]∗x[i])
,
∑(x[i]2)
,
∑(x[i])
吗 推完了式子感觉十分不虚,然而眼瞎选手又一次读错了题,以为自己只有50的部分分。
超级错误决定形成 t2->t3->t1
1h后
卧槽会爆。。。只有40了先搞t1再说
卧槽t1我为什么拍出了负环,难道我的建模崩了?作为被负环卡过的人,感觉很慌。调调调加上判断负环(然后就被卡常数了)。
4h
写t2吧 没调出来
4.95h
检查文件名+检查变量
70+10+0 = 80
总结
果然自己还是没有比赛经验,代码能力还是不够,如果最优决策走到底的话能多拿day1t2的10分暴力,day2t3的70暴力。。。感觉好虚。。。
果然要暂时afo了吗
bzoj动辄30s的时限害人不浅。
题解+代码
Day 2
T1
呃呃呃我就只说一下为什么不会有负环吧。
显然在负环一定不会包含S,T
假设是a->b->c->…->a这样一条路径,如果a可以走,那么显然s->是没有匹配的,而最后又回到了a,所以a又有反向边,矛盾,就酱。
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <climits>
#define MAX_N 205
#define EPS 1e-9
#define D_INF 1e6
#define I_INF 0x3f3f3f3f
//#define DEBUG
using namespace std;
struct Edge {
int d, cap, nxt; double cost;
Edge() { }
Edge(int d, int nxt, int cap, double cost) :
d(d), nxt(nxt), cap(cap), cost(cost) { }
} es[MAX_N * MAX_N * 4];
int G[MAX_N], estp;
void G_init() { memset(G, 0, sizeof(G)); estp = 1; }
void add_edge(int s, int d, int cap, double cost) {
es[++estp] = Edge(d, G[s], cap, cost); G[s] = estp;
es[++estp] = Edge(s, G[d], 0, -cost); G[d] = estp;
}
double dist[MAX_N]; int pree[MAX_N], prev[MAX_N];
int V, qhd, qtl, que[MAX_N], inqc[MAX_N]; bool inq[MAX_N];
inline int qpop() {
int k = que[qhd++]; inq[k] = false;
if (qhd == MAX_N) qhd = 0; return k;
}
inline bool qpush(int x) {
inq[x] = true; que[qtl++] = x;
if (qtl == MAX_N) qtl = 0;
if (++inqc[x] >= V - 1) return false;
else return true;
}
bool spfa(int s) {
fill(dist, dist + MAX_N, D_INF);
memset(pree, -1, sizeof(pree));
memset(prev, -1, sizeof(prev));
memset(inq, 0, sizeof(inq));
memset(inqc, 0, sizeof(inqc));
qhd = qtl = 0;
qpush(s); dist[s] = 0.0;
while (qhd != qtl) {
int v = qpop();
if (inqc[v] >= V - 1) return false;
for (int i = G[v];i;i = es[i].nxt) {
Edge &e = es[i];
if (e.cap > 0 && dist[e.d] > dist[v] + e.cost) {
dist[e.d] = dist[v] + e.cost;
pree[e.d] = i; prev[e.d] = v;
if (!inq[e.d]) {
bool flag = qpush(e.d);
if (!flag) return false;
}
}
}
}
return true;
}
double argu(int s, int t, bool &flag) {
int v, mxf = I_INF, vcnt = 1; double c = 0.0;
for (v = t;v != s;v = prev[v]) {
if(++vcnt >= V - 1) { flag = false; return D_INF; }
mxf = min(mxf, es[pree[v]].cap);
}
for (v = t;v != s;v = prev[v]) {
int k = pree[v]; c += es[k].cost * mxf;
es[k].cap -= mxf; es[k ^ 1].cap += mxf;
}
return c;
}
double mnc_mxf(int s, int t) {
double c = 0.0;
while (true) {
bool flag = spfa(s);
if (!flag) return D_INF;
if (prev[t] < 0) break;
c += argu(s, t,flag);
if(!flag) return D_INF;
}
return c;
}
int N, A[MAX_N][MAX_N], B[MAX_N][MAX_N], S, T;
bool check(double k) {
G_init(); V = N + N + 2;
int i, j; for (i = 1;i <= N;++i) {
add_edge(S, i, 1, 0); add_edge(N + i, T, 1, 0);
}
for (i = 1;i <= N;++i) for (j = 1;j <= N;++j)
add_edge(i, N + j, 1, -(A[i][j] - B[i][j] * k));
double c = -mnc_mxf(S, T);
return c >= EPS;
}
void solve() {
double l = 0.0, r = D_INF;
for (int k = 0;k < 52;++k) {
double mid = (l + r) / 2;
if (check(mid)) l = mid;
else r = mid;
}
printf("%.6f\n", l);
}
int main(int argc, char *argv[]) {
freopen("ball.in", "r", stdin);
freopen("ball.out", "w", stdout);
int i, j; scanf("%d", &N); S = N + N + 1, T = N + N + 2;
for (i = 1;i <= N;++i) for (j = 1;j <= N;++j) scanf("%d", &A[i][j]);
for (i = 1;i <= N;++i) for (j = 1;j <= N;++j) scanf("%d", &B[i][j]);
solve();
return 0;
}
update:
想了好久。。。。。
不如直接从古典概型的角度去理解。。。。
设N是所有的未匹配状态,我不管是它的长度为1或是100000000000,我就这么设。
然后把n加上一个人的串,可能会有很多种情况。
而且这一定是全部的概率了,因为我的N设成了所有的失配情况。
#include <cstdio>
#include <cstring>
#include <algorithm>
const int N = 305;
int n, m, fail[N]; char strs[N][N];
double pwt[N], mat[N][N];
int main(int argc, char *argv[]) {
int i, j, k, p; double sum = 0.0; scanf("%d%d", &n, &m);
for (i = 1;i <= n;++i) scanf("%s", strs[i] + 1);
for (i = 1, pwt[0] = 1.0;i <= m;++i) pwt[i] = 0.5 * pwt[i - 1];
for (i = 1;i <= n;++i) {
//把自己当作匹配串
for (p = 0, j = 2;j <= m;++j) {
//自己和自己匹配,算出系数。因为fail[0], fail[1],都永远是0所以也就没必要改了。
while (p && strs[i][j] != strs[i][p + 1]) p = fail[p];
fail[j] = (strs[i][j] == strs[i][p + 1]) ? ++p : p;
}
//注意自己的系数不一定是1,比如AAAAAA,也有可能是已经匹配了的车
for (j = 1;j <= n;++j) {
for (p = 0, k = 1;k <= m;++k) {
while (p && strs[j][k] != strs[i][p + 1]) p = fail[p];
if (strs[j][k] == strs[i][p + 1]) ++p;
}
for (;p;p = fail[p]) mat[i][j] += pwt[m - p];
}
//为了防止炸精度,定义(N*(0.5)^M=1.0)
mat[i][n + 1] = 1.0;
}
//板子
for (i = 1;i <= n;++i) {
for (j = i + 1;j <= n + 1;++j) mat[i][j] /= mat[i][i];
for (mat[i][i] = 1.0, j = i + 1;j <= n;mat[j][i] = 0.0, ++j)
for (k = i + 1;k <= n + 1;++k) mat[j][k] -= mat[i][k] * mat[j][i];
}
for (i = n;i >= 1;--i) for (j = i + 1;j <= n;++j) mat[i][n + 1] -= mat[i][j] * mat[j][n + 1];
for (i = 1;i <= n;++i) sum += mat[i][n + 1];
for (i = 1;i <= n;++i) printf("%.10f\n", mat[i][n + 1] / sum);
return 0;
}
T2
我只会40的暴力,考场上还因为次数问题被卡了。。。。。。
非常恶心,n=18的数据要生成到100000位以上。。。。。。
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cctype>
//#define DEBUG
#define MAX_N 20
using namespace std;
struct AhoCorasickAutomata {
static const int ndsz = MAX_N * MAX_N, sgmsz = 2, rt = 1;
int ch[ndsz][2], fail[ndsz], ndtp; bool ise[ndsz];
AhoCorasickAutomata() { ndtp = 1; }
inline int new_node() { return ++ndtp; }
inline int idx(char c) { return c == 'H' ? 0 : 1; }
int add(const char *s) {
int i, v = rt, n = strlen(s);
for (i = 0;i < n;++i) {
char c = idx(s[i]);
if (!ch[v][c]) ch[v][c] = new_node();
v = ch[v][c];
}
ise[v] = true; return v;
}
void get_fail() {
static int que[ndsz], qhd, qtl;
int i, v; qhd = qtl = 0;
for (i = 0;i < sgmsz;++i) {
if (ch[rt][i]) {
fail[ch[rt][i]] = rt; que[qtl++] = ch[rt][i];
}
else ch[rt][i] = rt;
}
while (qhd != qtl) {
v = que[qhd++];
for (i = 0;i < sgmsz;++i) {
if (ch[v][i]) {
fail[ch[v][i]] = ch[fail[v]][i];
ise[ch[v][i]] |= ise[fail[ch[v][i]]];
que[qtl++] = ch[v][i];
}
else ch[v][i] = ch[fail[v]][i];
}
}
}
} ac;
const int K = 140000;
int N, M, L[MAX_N]; double dp[K + 5][MAX_N * MAX_N][2];
int main(int argc, char *argv[]) {
freopen("game.in", "r", stdin);
freopen("game.out", "w", stdout);
int i, j, l; scanf("%d%d", &N, &M);
for (i = 0;i < N;++i) {
char s[MAX_N]; scanf("%s", s); L[i] = ac.add(s);
}
ac.get_fail();
dp[0][1][0] = 1.0;
for (i = 0;i < K;++i) for (j = 1;j <= ac.ndtp;++j) {
dp[i + 1][j][1] += dp[i][j][1];
for (l = 0;l < 2;++l) {
int ni = i + 1, nj = ac.ch[j][l], nk = ac.ise[nj] ? 1 : 0;
dp[ni][nj][nk] += dp[i][j][0] * 0.5;
}
}
#ifdef DEBUG
for (i = 0;i <= K;++i) for (j = 1;j <= ac.ndtp;++j)
for (k = 0;k < 2;++k) printf("dp[%d][%d][%d] = %f\n", i, j, k, dp[i][j][k]);
#endif
for (i = 0;i < N;++i) printf("%.10f\n", dp[K][L[i]][1]);
return 0;
}
T3
就是线段树。。。。
不过30行的push_down真心鬼畜。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <climits>
#define MAX_N 200050
using namespace std;
struct SegmentTree {
static const int mxsz = MAX_N * 4, rt = 1;
double xs[mxsz], xys[mxsz], ys[mxsz], xxs[mxsz];
double up, dn, tax[mxsz], tay[mxsz], dltx, dlty;
double *srcx, *srcy, rxs, rxys, rys, rxxs;
double ism[mxsz], iism[mxsz];
bool tsx[mxsz], tsy[mxsz];
int siz, s, t;
inline void assign(int &v, double x, double y) {
xs[v] = x; xys[v] = x * y;
ys[v] = y; xxs[v] = x * x;
tax[v] = tay[v] = 0.0;
}
inline void push_down(int v, int l, int r) {
int ls = v << 1, rs = v << 1 ^ 1;
if (tsx[v] || tsy[v]) {
double smlr = ism[v], smlr2 = iism[v];
double dx = tax[v], dy = tay[v], n = r - l + 1.0;
xs[v] = dx * n + smlr; ys[v] = dy * n + smlr;
xys[v] = dx * dy * n + smlr * (dx + dy) + smlr2;
xxs[v] = dx * dx * n + 2 * dx * smlr + smlr2;
if (r - l + 1 >= 2) {
tsx[ls] |= tsx[v]; tsx[rs] |= tsx[v];
tsy[ls] |= tsy[v]; tsy[rs] |= tsy[v];
tax[ls] = dx; tax[rs] = dx;
tay[ls] = dy; tay[rs] = dy;
}
tsx[v] = tsy[v] = false; tax[v] = tay[v] = 0.0;
}
if (tax[v] || tay[v]) {
double dx = tax[v], dy = tay[v], n = r - l + 1.0;
xys[v] += dy * xs[v] + dx * ys[v] + dx * dy * n;
xxs[v] += 2.0 * dx * xs[v] + dx * dx * n;
ys[v] += n * dy; xs[v] += n * dx;
if (r - l + 1 >= 2) {
tax[ls] += dx; tax[rs] += dx;
tay[ls] += dy; tay[rs] += dy;
}
tax[v] = tay[v] = 0.0;
}
}
void push_up(int v) {
int ls = v << 1, rs = v << 1 ^ 1;
xs[v] = xs[ls] + xs[rs]; xys[v] = xys[ls] + xys[rs];
ys[v] = ys[ls] + ys[rs]; xxs[v] = xxs[ls] + xxs[rs];
}
void build(int n, double *sx, double *sy) {
siz = n; srcx = sx; srcy = sy;
_build(rt, 1, siz);
}
void _build(int v, int l, int r) {
if (l == r) {
assign(v, srcx[l], srcy[l]);
ism[v] = (double) l; iism[v] = (double) l * l;
} else {
int mid = (l + r) >> 1, ls = v << 1, rs = v << 1 ^ 1;
_build(ls, l, mid); _build(rs, mid + 1, r);
push_up(v); ism[v] = ism[ls] + ism[rs]; iism[v] = iism[ls] + iism[rs];
}
}
double query(int l, int r) {
s = l, t = r; up = dn = 0.0;
rxys = rxs = rxxs = rys = 0.0;
_query(rt, 1, siz);
double n = r - l + 1.0;
up += rxys; up -= rxs / n * rys;
dn += rxxs; dn -= rxs / n * rxs;
return up / dn;
}
void _query(int v, int l, int r) {
push_down(v, l, r);
if (s <= l && r <= t) {
rxys += xys[v]; rxs += xs[v];
rxxs += xxs[v]; rys += ys[v];
}
else if (r < s || l > t) return;
else {
int mid = (l + r) / 2;
_query(v << 1, l, mid);
_query(v << 1 ^ 1, mid + 1, r);
push_up(v);
}
}
void update(int l, int r, double dx, double dy) {
dltx = dx, dlty = dy, s = l, t = r;
_update(rt, 1, siz);
}
void _update(int v, int l, int r) {
push_down(v, l, r);
if (s <= l && r <= t) {
tax[v] = dltx; tay[v] = dlty;
push_down(v, l, r);
}
else if (r < s || l > t) return;
else {
int mid = (l + r) / 2;
_update(v << 1, l, mid);
_update(v << 1 ^ 1, mid + 1, r);
push_up(v);
}
}
void _set(int v, int l, int r) {
push_down(v, l, r);
if (s <= l && r <= t) {
tsx[v] = tsy[v] = true;
tax[v] = dltx; tay[v] = dlty;
push_down(v, l, r);
}
else if (r < s || l > t) return;
else {
int mid = (l + r) / 2;
_set(v << 1, l, mid);
_set(v << 1 ^ 1, mid + 1, r);
push_up(v);
}
}
void set(int l, int r, double S, double T) {
s = l, t = r, dltx = S, dlty = T;
_set(rt, 1, siz);
}
} sgt;
int N, M; double X[MAX_N], Y[MAX_N];
void solve() {
int opt, L, R; double S, T;
sgt.build(N, X, Y);
while (M--) {
scanf("%d%d%d", &opt, &L, &R);
if (opt != 1) scanf("%lf%lf", &S, &T);
switch (opt) {
case 1: printf("%.5f\n", sgt.query(L, R)); break;
case 2: sgt.update(L, R, S, T); break;
case 3: sgt.set(L, R, S, T); break;
}
}
}
int main(int argc, char *argv[]) {
freopen("relative.in", "r", stdin);
freopen("relative.out", "w", stdout);
scanf("%d%d", &N, &M);
int i; for (i = 1;i <= N;++i) scanf("%lf", &X[i]);
for (i = 1;i <= N;++i) scanf("%lf", &Y[i]);
solve();
return 0;
}