3.12考试总结

A 小树

题意:51nod 1805
题解:prufer+容斥
由prufer序列性质,度数为1的点不会在里面出现
于是转化为一个长度为\(n-2\)的序列里,总共有\(n\)个元素,恰好有\(m\)个不出现
于是对\(m\)容斥(恰好->至少)
至少\(i\)个不出现的方案数是\(C_{n}^{i}*(n-i)^{n-2}\)
容斥系数是\((-1)^{i-m}*C_{i}^{m}\)
注意特判一下\(n\leq 2\),此时prufer序列不存在,答案为1

#include<bits/stdc++.h>
using namespace std;
#define P 1000000007
#define maxn 1000005
int n, m, inv[maxn], fac[maxn];
inline int qpow(int a, int b)
{
    int ans = 1;
    while (b)
    {
        if (b & 1) ans = 1ll * ans * a % P;
        a = 1ll * a * a % P;
        b >>= 1;
    }
    return ans;
}
inline int c(int x, int y)
{
    return 1ll * fac[x] * inv[y] % P * inv[x - y] % P;
}
int main()
{
    scanf("%d%d", &n, &m);
    if (n <= 2) puts("1");
    else
    {
        fac[0] = inv[0] = 1;
        for (int i = 1; i <= n; ++i) fac[i] = 1ll * fac[i - 1] * i % P;
        inv[n] = qpow(fac[n], P - 2);
        for (int i = n - 1; i; --i) inv[i] = 1ll * inv[i + 1] * (i + 1) % P;
        long long ans = 0;
        for (int i = m, f = 1; i <= n; ++i, f ^= 1)
        {
            if (f) ans += 1ll * c(i, m) * c(n, i) % P * qpow(n - i, n - 2) % P;
            else ans -= 1ll * c(i, m) * c(n, i) % P * qpow(n - i, n - 2) % P;
            ans %= P;
        }
        ans = (ans + P) % P;
        printf("%lld\n", ans);
    }
    return 0;
}

B 搬箱子

题意:51nod 1362
题解:组合数
考虑枚举斜着走了\(i\)
\begin{split}
F[n][m]&=\sum_{i=0}^{n}C_{n}^{i}C_{n+m-2i}^{n-i} \newline
&=\sum_{i=0}^{n}C_{n}^{i}C_{n+m-i}^{m-i}
\end{split}
因为最后一排任意一点都可以
所以
\begin{split}
Ans &=\sum_{j=0}^{m}{\sum_{i=0}^{n}C_{n}^{i}C_{n+j-i}^{j-i}}\newline
&=\sum_{i=0}^{n}C_{n}^{i}{\sum_{j=0}^{m}{C_{n+j-i}^{j-i}}}\newline
&=\sum_{i=0}^{n}C_{n}^{i}C_{n+m-i+1}^{m-i}
\end{split}
exlucas是什么辣鸡东西!直接分解质因数它不香吗!
这个struct是我本来蒯了以前的exlucas板子,结果T飞了,只好重写

#include<bits/stdc++.h>
using namespace std;
template<typename T>
struct Calculator
{
#define maxn 305
    int P, p[maxn], x, y, cnt, tim[maxn];
    void factor(int x)
    {
        for (int i = 2; i * i <= x; i++)
        {
            if (x % i) continue;
            p[++cnt] = i;
            while (x % i == 0) x /= i;
        }
        if (x > 1) p[++cnt] = x;
    }
    T qpow(T a, int b)
    {
        T ans = 1;
        while (b)
        {
            if (b & 1) ans = ans * a % P;
            a = a * a % P;
            b >>= 1;
        }
        return ans;
    }
    void exgcd(int a, int b, int& x, int& y)
    {
        if (!b)
        {
            x = 1, y = 0;
            return;
        }
        exgcd(b, a % b, y, x);
        y -= a / b * x;
    }
    inline int inv(int a, int b)
    {
        exgcd(a, b, x, y);
        return (x % b + b) % b;
    }
    int get(int x, int tp)
    {
        for (int i = 1; i <= cnt; i++)
        {
            if (x % p[i]) continue;
            int cnt = 0;
            while (x % p[i] == 0) ++cnt, x /= p[i];
            tim[i] += cnt * tp;
        }
        return x;
    }
    int C(int n, int m)
    {
        if (n < m) return 0;
        if (m == 0) return 1;
        memset(tim, 0, sizeof tim);
        T ans = 1;
        for (int i = n - m + 1; i <= n; i++)
            ans = ans * get(i, 1) % P;
        for (int i = 1; i <= m; i++)
            ans = ans * inv(get(i, -1), P) % P;
        for (int i = 1; i <= cnt; i++)ans = ans * qpow(p[i], tim[i]) % P;
        return ans;
    }
};
Calculator<long long> c;
int main()
{
    int n, m, X, ans = 0;
    while (scanf("%d%d%d", &n, &m, &X) != EOF)
    {
        ans = 0; c.P = X; c.factor(X);
        for (int i = 0; i <= n; ++i) ans = (0ll + ans + 1ll * c.C(n, i) * c.C(n + m - i + 1, n + 1)) % X;
        printf("%d\n", ans);
    }
    return 0;
}

C 七星剑

题意:51nod 1705
题解:期望
\(ans[i]\)为第\(i\)颗星的期望
\(i-1 \rightarrow i\)颗星时
\[ans[i]=ans[i-1]+c[i][j]+(1-prob[i][j)*(ans[i]-ans[i-1-lose[i][j]])\]
化简得
\[ans[i]=\frac{ans[i-1]+c[i][j]-(1-prob[i][j])*ans[i-1-lose[i][j]]}{prob[i][j]}\]

#include<bits/stdc++.h>
using namespace std;
#define maxn 105
#define db long double
#define eps 1e-10
int n, c[maxn], lose[8][maxn];
db prob[8][maxn], ans[maxn];
inline int cmp(db a)
{
    if (a > eps) return 1;
    if (a < -eps) return -1;
    return 0;
}
int main()
{
    scanf("%d", &n);
    for (int i = 1; i <= n; ++i) scanf("%d", &c[i]);
    for (int i = 1; i <= 7; ++i)
    {
        int flag = 0;
        for (int j = 1; j <= n; ++j)
        {
            scanf("%Lf", &prob[i][j]);
            if (cmp(prob[i][j])) flag = 1;
        }
        if (flag == 0)
        {
            puts("-1");
            return 0;
        }
    }
    for (int i = 1; i <= 7; ++i)
        for (int j = 1; j <= n; ++j) scanf("%d", &lose[i][j]);
    for (int i = 1; i <= 7; ++i)
    {
        ans[i] = 1e20;//1e9会爆掉
        for (int j = 1; j <= n; ++j)
            if (cmp(prob[i][j])) 
                            ans[i] = min(ans[i], (ans[i - 1] + c[j] - (1 - prob[i][j]) * ans[i - 1 - lose[i][j]]) / prob[i][j]);
    }
    printf("%.12Lf", ans[7]);
    return 0;
}

D 棋盘游戏

题意:51nod 1327
题解:咕咕咕

猜你喜欢

转载自www.cnblogs.com/123789456ye/p/12497878.html