2016 ACM/ICPC亚洲区沈阳站

Posted mrzdtz220

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2016 ACM/ICPC亚洲区沈阳站相关的知识,希望对你有一定的参考价值。

 

[A. Thickest Burger]

签到。

 

[B. Relative atomic mass]

签到

 

[C. Recursive sequence]

$$f[i] = f[i - 1] + 2 * f[i - 2] + i ^ 4$$

$$
left[
egin{matrix}
1 & 2 & 1 & 0 & 0 & 0 & 0 \
1 & 0 & 0 & 0 & 0 & 0 & 0\
0 &0 & 1 & 4 & 6 &4 & 1 \
0 & 0 & 0 & 1 & 3 & 3 & 1 \
0 & 0 & 0 & 0 & 1 & 2 & 1 \
0 & 0 & 0 & 0 & 0 & 1 & 1 \
0 & 0 & 0 & 0 & 0 & 0 & 1
end{matrix}
ight]
imes
left[
egin{matrix}
f_{i-1} & 0 & 0 & 0 & 0 & 0 & 0 \
f_{i-2} & 0 & 0 & 0 & 0 & 0 & 0\
i^4 &0 & 0 & 0& 0 &0 & 0 \
i^3 & 0 & 0 & 0 & 0 & 0 & 0 \
i^2 & 0 & 0 & 0 & 0 & 0 & 0\
i & 0 & 0 & 0 & 0 & 0 & 0 \
1 & 0 & 0 & 0 & 0 & 0 & 0
end{matrix}
ight]=
left[
egin{matrix}
f_{i} & 0 & 0 & 0 & 0 & 0 & 0 \
f_{i} & 0 & 0 & 0 & 0 & 0 & 0\
(i+1)^4 &0 & 0 & 0& 0 &0 & 0 \
(i+1)^3 & 0 & 0 & 0 & 0 & 0 & 0 \
(i+1)^2 & 0 & 0 & 0 & 0 & 0 & 0\
i+1 & 0 & 0 & 0 & 0 & 0 & 0 \
1 & 0 & 0 & 0 & 0 & 0 & 0
end{matrix}
ight]
$$

技术图片
#include <bits/stdc++.h>
#define ll long long

const ll MOD = 2147493647;
const int N = 7;

struct Mat {
    ll a[10][10];
    Mat() {
        memset(a, 0, sizeof(a));
    }
    Mat(int x) {
        memset(a, 0, sizeof(a));
        for (int i = 1; i <= N; i++)
            a[i][i] = 1;
    }
    Mat operator * (const Mat &rhs) const {
        Mat c;
        for (int i = 1; i <= N; i++)
            for (int j = 1; j <= N; j++)
                for (int k = 1; k <= N; k++)
                    c.a[i][j] = (c.a[i][j] + a[i][k] * rhs.a[k][j] % MOD) % MOD;
        return c;
    }
};

Mat qp(Mat a, int b) {
    Mat c(1);
    while (b) {
        if (b & 1) c = a * c;
        a = a * a;
        b >>= 1;
    }
    return c;
}

int main() {
    int T;
    scanf("%d", &T);
    Mat base;
    base.a[1][1] = 1; base.a[1][2] = 2; base.a[1][3] = 1;
    base.a[2][1] = 1;
    base.a[3][3] = 1; base.a[3][4] = 4; base.a[3][5] = 6; base.a[3][6] = 4; base.a[3][7] = 1;
    base.a[4][4] = 1; base.a[4][5] = 3; base.a[4][6] = 3; base.a[4][7] = 1;
    base.a[5][5] = 1; base.a[5][6] = 2; base.a[5][7] = 1;
    base.a[6][6] = 1; base.a[6][7] = 1;
    base.a[7][7] = 1;
    while (T--) {
        int n, a, b;
        scanf("%d%d%d", &n, &a, &b);
        if (n == 1) {
            printf("%d
", a);
            continue;
        }
        if (n == 2) {
            printf("%d
", b);
            continue;
        }
        n--;
        n--;
        Mat ans;
        ans.a[1][1] = b; ans.a[2][1] = a; ans.a[3][1] = 81; ans.a[4][1] = 27; ans.a[5][1] = 9; ans.a[6][1] = 3; ans.a[7][1] = 1;
        ans = qp(base, n) * ans;
        printf("%lld
", ans.a[1][1] % MOD);
    }
    return 0;
}
View Code

 

[E. Counting Cliques]

经过暑假牛客多校的洗礼,看到团就想到暴搜...

首先用了bfs+bitset。T了。

改成vector判,又T了。

看了一份题解是dfs,存团的是数组。

我把那份代码的数组改成vector,还是T。

这么卡STL的吗...

技术图片
#include <bits/stdc++.h>

const int N = 107;
std::vector<int> G[N];
bool mp[N][N];

int ans, n, m, s;

void solve(int *a, int u) {
    if (a[0] == s) {
        ans++;
        return;
    }
    for (int v: G[u]) {
        if (v <= u) continue;
        bool flag = 1;
        for (int j = 1; j <= a[0]; j++) {
            if (!mp[a[j]][v]) {
                flag = 0;
                break;
            }
        }
        if (!flag) continue;
        a[++a[0]] = v;
        solve(a, v);
        --a[0];
    }
}

int a[N];

int main() {
    int T;
    scanf("%d", &T);
    while (T--) {
        scanf("%d%d%d", &n, &m, &s);
        for (int i = 0; i <= n; i++) {
            G[i].clear();
            for (int j = 0; j <= n; j++)
                mp[i][j] = 0;
            a[i] = 0;
        }
        for (int i = 0; i < m; i++) {
            int u, v;
            scanf("%d%d", &u, &v);
            if (u > v) std::swap(u, v);
            G[u].push_back(v);
            mp[u][v] = mp[v][u] = 1;
        }
        ans = 0;
        for (int i = 1; i <= n; i++) {
            a[0] = 1;
            a[1] = i;
            solve(a, i);
        }
        printf("%d
", ans);
    }
    return 0;
}
View Code

 

[H. Guessing the Dice Roll]

先把AC自动机建出来。在AC自动机上DP。

$dp[i] = sum frac{1}{6} imes dp[from]$

$from$ 为能转到 $i$ 且不为某个串的结尾的结点

因为会存在环,所以高斯消元就行了。

技术图片
#include <bits/stdc++.h>

const int N = 100 + 7;

double mat[N][N];
const double eps = 1e-8;

inline void gauss(int n) {
    for(int i = 0; i <= n; i++) {
        int r = i;
        for(int j = i + 1; j <= n; j++)
            if(std::fabs(mat[r][i]) < std::fabs(mat[j][i])) 
                r = j;
        if(r != i) std::swap(mat[i], mat[r]);
        for(int j = 0; j <= n; j++) {
            if(j == i) continue;
            double t = mat[j][i] / mat[i][i];
            for(int k = i; k <= n + 1; k++)
                mat[j][k] -= mat[i][k] * t;
        }
    }
    for(int i = 1; i <= n; i++) {
        mat[i][n + 1] /= mat[i][i];
    }
} 

struct Aho {
    static const int sz = 6;
    int ch[N][sz], last[N], fail[N], tol;
    bool end[N];
    void init() {
        tol = 0;
        newnode();
    }
    inline int newnode() {
        memset(ch[tol], 0, sizeof(ch[tol]));
        last[tol] = fail[tol] = end[tol] = 0;
        return tol++;
    }
    void insert(int *a, int n) {
        int u = 0;
        for (int i = 0; i < n; i++) {
            int id = a[i] - 1;
            if (!ch[u][id]) ch[u][id] = newnode();
            u = ch[u][id];
        }
        end[u] = 1;
    }
    void build() {
        std::queue<int> que;
        for (int i = 0; i < sz; i++)
            if (ch[0][i]) que.push(ch[0][i]), fail[ch[0][i]] = last[ch[0][i]] = 0;
        while (!que.empty()) {
            int u = que.front(); que.pop();
            end[u] |= end[last[u]];
            for (int i = 0; i < sz; i++) {
                int &v = ch[u][i];
                if (v) {
                    fail[v] = ch[fail[u]][i];
                    que.push(v);
                    last[v] = end[fail[v]] ? fail[v] : last[fail[v]];
                } else {
                    v = ch[fail[u]][i];
                }
            }
        }
    }
    void solve() {
        memset(mat, 0, sizeof(mat));
        mat[0][tol] = -1.0;
        for (int i = 0; i < tol; i++) {
            mat[i][i] = -1.0;
            if (end[i]) continue;
            for (int j = 0; j < sz; j++)
                mat[ch[i][j]][i] += 1.0 / 6;
        }
        gauss(tol - 1);
        bool flag = 0;
        for (int i = 0; i < tol; i++)
            if (end[i]) {
                if (flag) putchar( );
                printf("%.6f", mat[i][tol]);
                flag = 1;
            }
        puts("");
    }
} ac;

int a[20];

int main() {
    int T;
    scanf("%d", &T);
    for (; T--; ) {
        int n, l;
        scanf("%d%d", &n, &l);
        ac.init();
        for (int i = 1; i <= n; i++) {
            for (int j = 0; j < l; j++)
                scanf("%d", a + j);
            ac.insert(a, l);
        }
        ac.build();
        ac.solve();
    }
    return 0;
}
View Code

 

[I. The Elder]

$dp[u] = min(dp[anc] + (sum[u] - sum[anc])^2 + p)$

$anc$ 为 $u$ 到根的路径上的结点。

斜率优化DP一下。在进入一个结点时存储一下对当前队列的修改,离开一个结点时改回去,这样就能保证进入一个结点时,队列存储的都是它的祖先。

技术图片
#include <bits/stdc++.h>
#define pii pair<int, int>
#define ll long long
#define fi first
#define se second

const int N = 1e5 + 7;
const double eps = 1e-10;
ll dp[N];
int n, p, que[N], l, r;
ll sum[N];
std::vector<std::pii> G[N];

inline ll sqr(ll x) {
    return x * x;
}

inline ll up(int i, int j) {
    return dp[i] + sqr(sum[i]) - dp[j] - sqr(sum[j]);
}

inline ll down(int i, int j) {
    return sum[i] - sum[j];
}

ll ans;

void dfs(int u, int fa = 0) {
    std::vector<std::pii> vec;
    int x = l, y = r;
    while (l < r && up(que[l + 1], que[l]) <= down(que[l + 1], que[l]) * 2 * sum[u]) {
        vec.push_back(std::pii(l, que[l]));
        l++;
    }
    if (u != 1) {
        dp[u] = dp[que[l]] + sqr(sum[u] - sum[que[l]]) + p;
        ans = std::max(ans, dp[u]);
    }
    while (l < r && up(que[r], que[r - 1]) * down(u, que[r]) >= up(u, que[r]) * down(que[r], que[r - 1])) {
        vec.push_back(std::pii(r, que[r]));
        r--;
    }
    que[++r] = u;
    for (auto v: G[u]) {
        if (v.fi == fa) continue;
        sum[v.fi] = sum[u] + v.se;
        dfs(v.fi, u);
    }
    l = x, r = y;
    for (auto p: vec)
        que[p.fi] = p.se;
}

int main() {
    int T;
    scanf("%d", &T);
    while (T--) {
        scanf("%d%d", &n, &p);
        for (int i = 1; i <= n; i++) 
            dp[i] = sum[i] = 0, G[i].clear();
        for (int i = 1, u, v, w; i < n; i++) {
            scanf("%d%d%d", &u, &v, &w);
            G[u].push_back(std::pii(v, w));
            G[v].push_back(std::pii(u, w));
        }
        dp[1] = -p;
        que[l = r = 1] = 0;
        ans = 0;
        dfs(1);
        printf("%lld
", ans);
    }
    return 0;
}
View Code

 

以上是关于2016 ACM/ICPC亚洲区沈阳站的主要内容,如果未能解决你的问题,请参考以下文章

2016 ACM/ICPC亚洲区沈阳站

2016ACM/ICPC亚洲区沈阳站

2016ACM/ICPC亚洲区沈阳站 Solution

2016ACM/ICPC亚洲区沈阳站-重现赛

HDU 5950 Recursive sequence 递推+矩阵快速幂 (2016ACM/ICPC亚洲区沈阳站)

HDU 5950 - Recursive sequence - [矩阵快速幂加速递推][2016ACM/ICPC亚洲区沈阳站 Problem C]