2019.10.8 模拟赛

I don't like Matrix

T1 I liked Matrix

(n*m) 的矩阵A中所有位置中随机填入0或1,概率比为 (x:y) ,令 (B_i=sumlimits_{j=1}^{m}A_{i,j}) ,求 (min(B_i)) 的期望,将期望乘 ((x+y)^{nm}) 后模 (1000000007) 的值

导公式开始:(官方题解)

[E = sumlimits_{i = 1}^{m}i*P(min{B_i}= i) = sumlimits_{i = 1}^{m}P(min{B_i} geq i) $$ $$=sumlimits_{i = 1}^{m}P(B_i geq i)^n = sumlimits_{i = 1}^{m}(sumlimits_{j = i}^{m}P(B_i = j))^n $$ $$=sumlimits_{i = 1}^{m}(sumlimits_{j = i}^{m} frac{C_{m}^{j} * x^{m - j} * y ^ j}{(x + y)^m} )^n ]

[ans = sumlimits_{i = 1}^{m}(sumlimits_{j = i}^{m}C_m^j * x^{m - j} * y ^ j)^n ]

//节省空间以后放代码片段
const int MAXM = 2e5 + 5;
const int MOD = 1e9 + 7;
int jx[MAXM] = {1}, jy[MAXM] = {1};
int jc[MAXM] = {1}, jc_inv[MAXM];
int a[MAXM];
int n, m, x, y;
int main()
{
    poread(n), poread(m), poread(x), poread(y);
    for (register int i = 1; i <= m; ++i)
        jx[i] = (long long)jx[i - 1] * x % MOD;
    for (register int j = 1; j <= m; ++j)
        jy[j] = (long long)jy[j - 1] * y % MOD;
    for (register int i = 1; i <= m; ++i)
        jc[i] = (long long)jc[i - 1] * i % MOD;
    jc_inv[m] = qpow(jc[m], MOD - 2);
    for (register int i = m; i; --i)
        jc_inv[i - 1] = (long long)jc_inv[i] * i % MOD;
    for (register int i = 1; i <= m; ++i)
        jc[i] = (long long)jc[m] * jc_inv[i] % MOD * jc_inv[m - i] % MOD;
    for (register int i = m; i >= 1; --i)
        a[i] = (a[i + 1] + (long long)jc[i] * jx[m - i] % MOD * jy[i] % MOD) % MOD;
    static int ans;
    for (register int i = 1; i <= m; ++i)
        ans = (ans + qpow(a[i], n)) % MOD;
    cout << ans << endl;
}

T2 I like Matrix

(n*m) 的零矩阵A进行Q次操作:
(1 i j) :将 (A_{i,j}) 取反 ((xor 1))
(2 i) :将 (A) 矩阵第 (i) 行的所有元素取反
(3 j) :将 (A) 矩阵第 (j) 列的所有元素取反
(4 k) :将 (A) 矩阵还原成第 (k) 次操作之后的状态
上来就考虑可持久化?数据结构学傻的我。
我们发现所有的操作构成了一棵树。
所以直接按照操作顺序建树并dfs时进行计算就可以了。由于是异或操作所以异或还会变回去,一遍dfs统计答案即可。

const int MAXQ = 1e5 + 1;
const int MAXN = 1e3 + 1;
short n, m;
int q;
struct nde
{
    short opt, i, j;
} que[MAXQ];
int Ans[MAXQ];
bool b[MAXN][MAXN];
int ans;
inline void change(const int &t)
{
    short int tx = que[t].i, ty = que[t].j;
    if (que[t].opt == 1)
    {
        ans += b[tx][ty] ? -1 : 1;
        b[tx][ty] = b[tx][ty] ^ 1;
        return;
    }
    else if (que[t].opt == 2)
    {
        for (register int j = 1; j <= m; ++j)
        {
            ans += b[tx][j] ? -1 : 1;
            b[tx][j] = b[tx][j] ^ 1;
        }
        return;
    }
    else if (que[t].opt == 3)
    {
        for (register int j = 1; j <= n; ++j)
        {
            ans += b[j][tx] ? -1 : 1;
            b[j][tx] = b[j][tx] ^ 1;
        }
        return;
    }
}
struct Ro
{
    int nxt, ver;
} e[MAXQ];
int head[MAXQ], tot = 0;
inline void add(const int &x, const int &y)
{
    e[++tot].ver = y;
    e[tot].nxt = head[x];
    head[x] = tot;
}
inline void dfs(int x)
{
    change(x);
    Ans[x] = ans;
    for (register int i = head[x]; i; i = e[i].nxt)
        dfs(e[i].ver);
    change(x);
}
int main()
{
    poread(n), poread(m), poread(q);
    for (register int i = 1; i <= q; ++i)
    {
        poread(que[i].opt);
        if (que[i].opt == 4)
        {
            register int x;
            poread(x);
            add(x, i);
            continue;
        }
        poread(que[i].i);
        if (que[i].opt == 1)
            poread(que[i].j);
        add(i - 1, i);
    }
    for (register int i = head[0]; i; i = e[i].nxt)
        dfs(e[i].ver);
    for (register int i = 1; i <= q; ++i)
    {
        printf("%d", Ans[i]);
        putchar('
');
    }
}

T3 I will like Matrix

(1)(n*m) 之间的所有整数分别填入一个 (n*m) 的矩阵中,并要求其中的 (k) 个元素为局部极小值,即该元素小于周围的八个元素(如果存在),其他元素不做要求。求一共有多少种不同的矩阵,并将答案对 (1e9+7) 取模。保证一定存在合法的矩阵。

状态压缩DP计数。
(暴力计算s状态还有几个点能放数字g[s])
f[i][s] 表示放了第i小的数字,当前覆盖状态为s的方案数。
转移:
f[i+1][s∣(2 j−1 )]+=f[i][s]
f[i+1][s]+=f[i][s]∗(g[s]−i+cnt)

struct node
{
    int x, y;
} poi[MAXK];
int f[MAXK << 3][1 << MAXK];
int cnt[1 << MAXK];
int g[1 << MAXK];
int jc[10001] = {1}, jc_inv[10001] = {1};
bool vis[MAXN][MAXN], check[MAXN][MAXN];
int tot;
signed main()
{
    poread(n), poread(m), poread(k);
    for (register int i = 1; i <= n * m; ++i)
        jc[i] = (long long)jc[i - 1] * i % MOD;
    jc_inv[n * m] = qpow(jc[n * m], MOD - 2);
    for (register int i = n * m; i; --i)
        jc_inv[i - 1] = (long long)jc_inv[i] * i % MOD;
    for (register int i = 0; i < k; ++i)
    {
        poread(poi[i].x), poread(poi[i].y);
        check[poi[i].x][poi[i].y] = true;
    }
    for (register int i = 0; i < k; ++i)
    {
        for (register int xi = max(1, poi[i].x - 1); xi <= min(n, poi[i].x + 1); ++xi)
        {
            for (register int yi = max(1, poi[i].y - 1); yi <= min(m, poi[i].y + 1); ++yi)
            {
                if (vis[xi][yi] || check[xi][yi])
                    continue;
                vis[xi][yi] = true;
                ++tot;
            }
        }
    }
    for (register int s = 0; s < (1 << k); ++s)
    {
        memset(vis, 0, sizeof(vis));
        register int cnt = 0;
        for (register int i = 0; i < k; ++i)
        {
            if (s & (1 << i))
                continue;
            for (register int xi = max(1, poi[i].x - 1); xi <= min(n, poi[i].x + 1); ++xi)
            {
                for (register int yi = max(1, poi[i].y - 1); yi <= min(m, poi[i].y + 1); ++yi)
                {
                    if (vis[xi][yi] || check[xi][yi])
                        continue;
                    vis[xi][yi] = true;
                    ++cnt;
                }
            }
        }
        g[s] = tot - cnt;
    }
    f[0][0] = 1;
    for (register int i = 0; i < tot + k; ++i)
    {
        for (register int s = 0; s < (1 << k); ++s)
        {
            register int cnt = 0;
            for (register int j = 0; j < k; ++j)
            {
                if (s & (1 << j))
                    continue;
                f[i + 1][s | (1 << j)] = (1ll * f[i + 1][s | (1 << j)] + f[i][s]) % MOD;
                ++cnt;
            }
            cnt = k - cnt;
            if (g[s] - i + cnt > 0)
                f[i + 1][s] = 1ll * (f[i + 1][s] + (f[i][s] * ((g[s] - i + cnt + MOD) % MOD) % MOD)) % MOD;
        }
    }
    printf("%d
", 1ll * f[tot + k][(1 << k) - 1] * jc[n * m] % MOD * jc_inv[tot + k] % MOD);
    return 0;
}
晚上赶时间写的博客可能出锅

部分内容来自nofind的博客

原文地址:https://www.cnblogs.com/Shiina-Rikka/p/11651577.html