SDOI 2017 Round 1 滚粗记

游记

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;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值