省选测试31

A coin

题目大意 : 给出每个人喜欢每个物品的概率,问期望满意人数的最大值

  • 可以贪心的选可以增加期望最大的物品,用个堆就行

  • 设f[k][c][n]表示前i个人c个k物品的期望,增加的期望就是f[k][c][n]-f[k][c-1][n]

  • 转移的话就看这个人喜欢的是这个物品,或不是这个物品

Code

Show Code
#include <queue>
#include <vector>
#include <cstdio>

using namespace std;
const int N = 3005, M = 305;

int read(int x = 0, int f = 1, char c = getchar()) {
    for (; c < '0' || c > '9'; c = getchar()) if (c == '-') f = -1;
    for (; c >='0' && c <='9'; c = getchar()) x = x * 10 + c - '0';
    return x * f;
}

int n, m, s[M];
double p[N][M], ans;
vector<double> f[M][N];
priority_queue< pair<double, int> > q;

double F(int k, int c, int n) {
    while (!p[n][k] && n) n--;
    if (!c || !n) return 0.0;
    if (f[k][c][n]) return f[k][c][n];
    return f[k][c][n] = (1 + F(k, c - 1, n - 1)) * p[n][k] + F(k, c, n - 1) * (1 - p[n][k]);
}

int main() {
    n = read(); m = read();
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= m; ++j)
            p[i][j] = read() / 1000.0;
    for (int i = 1; i <= m; ++i) {
        f[i][1].resize(n + 1);
        q.push(make_pair(F(i, 1, n), i));
    }
    for (int i = 1; i <= n; ++i) {
        int x = q.top().second; ans += q.top().first;
        q.pop(); s[x]++;
        f[x][s[x]+1].resize(n + 1);
        q.push(make_pair(F(x, s[x] + 1, n) - F(x, s[x], n), x));
    }
    printf("%.10lf
", ans);
    return 0;
}

B B

题目大意 : n个点的树,断k条边再脸上k条边共会出现多少种树

  • 先矩阵树定理再来个高斯消元,复杂度n4

  • 还可以容斥,复杂度n2,不过没有写

Code

Show Code
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
const int N = 55, M = 998244353;

int read(int x = 0, int f = 1, char c = getchar()) {
    for (; c < '0' || c > '9'; c = getchar()) if (c == '-') f = -1;
    for (; c >='0' && c <='9'; c = getchar()) x = x * 10 + c - '0';
    return x * f;
}

bool v[N][N];
int a[N][N], b[N][N], n, m, ans;

int Pow(int a, int k = M - 2, int ans = 1) {
    for (; k; k >>= 1, a = 1ll * a * a % M)
        if (k & 1) ans = 1ll * ans * a % M;
    return ans;
}

int Det(int n) {
    int ans = 1;
    for (int i = 1; i <= n; ++i) {
        for (int j = i + 1; j <= n && !a[i][i]; ++j)
            if (a[j][i]) swap(a[i], a[j]), ans = M - ans;
        int inv = Pow(a[i][i]);
        for (int j = i + 1; j <= n; ++j) {
            if (!a[j][i]) continue;
            int tmp = 1ll * a[j][i] * inv % M;
            for (int k = i; k <= n; ++k)
                if ((a[j][k] -= 1ll * a[i][k] * tmp % M) < 0) a[j][k] += M;
        }
        ans = 1ll * ans * a[i][i] % M;
    }
    return ans;
}

void Gs(int (*a)[N]) {
    for (int i = 1; i <= n; ++i) {
        for (int j = i + 1; j <= n && !a[i][i]; ++j)
            if (a[j][i]) swap(a[i], a[j]);
        int inv = Pow(a[i][i]);
        for (int j = i + 1; j <= n; ++j) {
            if (!a[j][i]) continue;
            int tmp = 1ll * a[j][i] * inv % M;
            for (int k = i; k <= n + 1; ++k)
                if ((a[j][k] -= 1ll * a[i][k] * tmp % M) < 0) a[j][k] += M;
        }
    }
    for (int i = n; i >= 1; --i) {
        int sum = 0;
        for (int j = i + 1; j <= n; ++j)
            sum = (sum + 1ll * a[i][j] * a[j][j]) % M;
        a[i][i] = 1ll * (a[i][n+1] - sum + M) * Pow(a[i][i]) % M;
    }
}

int main() {
#ifdef Shawk
    freopen("in", "r", stdin);
#endif
    n = read(); m = read();
    for (int i = 2; i <= n; ++i) {
        int x = read() + 1;
        v[x][i] = v[i][x] = 1;
    }
    for (int k = 1; k <= n; ++k) {
        memset(a, 0, sizeof(a));
        for (int i = 1; i <= n; ++i) {
            for (int j = 1; j <= n; ++j) {
                if (i == j) continue;
                int x = v[i][j] ? 1 : k;
                if ((a[i][j] -= x) < 0) a[i][j] += M;
                if ((a[i][i] += x) >= M) a[i][i] -= M;
            }
        }
        b[k][1] = 1; b[k][n+1] = Det(n - 1);
        for (int i = 2; i <= n; ++i)
            b[k][i] = 1ll * b[k][i-1] * k % M;
        //printf("%d %d
", k, b[k][n+1]);
    }
    Gs(b);
    for (int i = 1; i <= m + 1; ++i)
        if ((ans += b[i][i]) >= M) ans -= M;
    printf("%d
", ans);
    return 0;
}

C battery

题目大意 : 炮台可以横着摆放,也可以竖着摆放,两端都可以发射激光。图中有反射镜,问怎样摆放才能让炮台达不到炮台并且每个空地都会被激光经过

  • 很容易想到对炮台横竖摆放做2-sat,但是不好保证每个空地的都能被经过

  • 我们再考虑,每个空地在横着或竖着不可能会被两个以上的炮台经过,因为这样如果想让这个空地被激光经过,这条激光一定会打到炮台

  • 所以可以找到横竖两个方向经过空地的炮台,要求要空地必须有激光,如果炮台没有被经过,就无解;如果只被一个炮台经过,这个炮台强制选这个方向;
    如果被两个炮台经过,那一个炮台换别的方向的时候另一个就得强制在这个方向

  • 当然如果有炮台横竖都能打到炮台,也是无解

  • 接下来2-sat就行了

Code

Show Code
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
const int N = 55, M = N * N * 2;

struct Edge {
    int n, t;
}e[M];
int h[M], edc;

void Add(int x, int y) {
    e[++edc] = (Edge) {h[x], y}; h[x] = edc;
}

bool g;
char s[N][N];
int n, m, c0, c1, id[N][N], stk[M], tp, b[M][2];
int dfn[M], dfc, low[M], c[M], cnt, px[M], py[M];
int dx[] = {0, 1, -1, 0}, dy[] = {1, 0, 0, -1};
//u2,d1,l3,r0

void Dfs(int x, int y, int k) {
    while(g) {
        x += dx[k], y += dy[k];
        if (s[x][y] == '-') g = 0;
        if (s[x][y] == '.') stk[++tp] = id[x][y];
        if (s[x][y] == '#' || !s[x][y]) return;
        if (s[x][y] == '\') k ^= 1;
        if (s[x][y] == '/') k ^= 2;
    }
}

void Tarjan(int x) {
    dfn[x] = low[x] = ++dfc; stk[++tp] = x;
    for (int i = h[x], y; i; i = e[i].n) {
        if (!dfn[y=e[i].t]) Tarjan(y), low[x] = min(low[x], low[y]);
        else if (!c[y]) low[x] = min(low[x], dfn[y]);
    }
    if (dfn[x] == low[x] && ++cnt) while (1) {
        c[stk[tp]] = cnt;
        if (stk[tp--] == x) break;
    }
}

void Solve() {
    scanf("%d%d", &n, &m);
    memset(s[n+1] + 1, 0, m);
    memset(b + 1, 0, c0 * 8);
    memset(c + 1, 0, c1 * 8);
    memset(h + 1, 0, c1 * 8);
    memset(dfn + 1, 0, c1 * 8);
    c0 = edc = dfc = cnt = 0; c1 = 1;
    for (int i = 1; i <= n; ++i) {
        scanf("%s", s[i] + 1);
        for (int j = 1; j <= m; ++j) {
            if (s[i][j] == '.') id[i][j] = ++c0;
            if (s[i][j] == '|') s[i][j] = '-';
        }
    }
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= m; ++j) {
            if (s[i][j] != '-') continue;
            c1++, px[c1] = i; py[c1] = j;
            g = 1; Dfs(i, j, 0); Dfs(i, j, 3); bool tmp = g;
            if (!g) tp = 0;
            while (tp) (b[stk[tp]][0] ? b[stk[tp]][1] : b[stk[tp]][0]) = c1, tp--;
            c1++;
            g = 1; Dfs(i, j, 1); Dfs(i, j, 2);
            if (!g) tp = 0;
            while (tp) (b[stk[tp]][0] ? b[stk[tp]][1] : b[stk[tp]][0]) = c1, tp--;
            if (!tmp && !g) return puts("IMPOSSIBLE"), void();
            if (!tmp) Add(c1 - 1, c1);
            if (!g) Add(c1, c1 - 1);
        }
    }
    for (int i = 1; i <= c0; ++i) {
        if (b[i][0] && b[i][1]) Add(b[i][0] ^ 1, b[i][1]), Add(b[i][1] ^ 1, b[i][0]);
        else if (b[i][0]) Add(b[i][0] ^ 1, b[i][0]);
        else return puts("IMPOSSIBLE"), void();
    }
    for (int i = 2; i <= c1; ++i)
        if (!dfn[i]) Tarjan(i);
    for (int i = 2; i <= c1; i += 2) {
        if (c[i] == c[i+1]) return puts("IMPOSSIBLE"), void();
        else if (c[i] > c[i+1]) s[px[i]][py[i]] = '|';
    }
    puts("POSSIBLE");
    for (int i = 1; i <= n; ++i)
        printf("%s
", s[i] + 1);
}

int main() {
    int T; scanf("%d", &T);
    while (T--) Solve();
    return 0;
}
原文地址:https://www.cnblogs.com/shawk/p/14457291.html