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的博客