[ABC310] D~F 题解
[ABC310] D~F 题解
D - Peaceful Teams
暴力搜索,搜索每个人在的队伍,为了去重,在一个人第一次加入新的队伍之后跳出。
bitset<N> st;
void dfs(int u)
{
for(int i = 1; i <= m; i ++)
if(pos[a[i]] && pos[b[i]] && pos[a[i]] == pos[b[i]]) return ;
if(u > n) return (void)(ans += st.count() == k);
for(int i = 1; i <= k; i ++) {
if(st[i])
pos[u] = i, dfs(u + 1), pos[u] = 0;
else {
st.set(i), pos[u] = i, dfs(u + 1), st.reset(i), pos[u] = 0;
return ;
}
}
}
E - NAND repeatedly
观察到如果一个区间以 \(0\) 为右端点,那么这个区间的 NAND
一定是 \(1\),如果我们已经算出了前 \(i - 1\) 位中答案为 \(0, 1\) 的区间个数,那么如果第 \(i\) 位是 \(1\),答案为 \(0, 1\) 的区间个数互换,并且 \(1\) 的区间个数加一,重复执行上述过程即可。
int ans = 0, cnt0 = 0, cnt1 = 0;
for(int i = 0; i < n; i ++) {
if(s[i] == '1') swap(cnt0, cnt1), cnt1 ++;
else cnt0 = 1, cnt1 = i;
ans += cnt1;
}
F - Make 10 Again
显然的状态表示:\(dp[i][j]\) 表示前 \(i\) 个骰子里选出若干,表示成 \(j\) 的概率。
然而这样会重复计算同一种随机下的贡献。
考虑用状态压缩优化状态表示,\(dp[i][s]\) 表示前 \(i\) 个骰子里选出若干,能够表示的集合为 \(s\) 的概率,然后就可以进行转移了。注意如果一个数 \(> 10\),它可以选择投出 \(> 10\) 的数让集合不变。
dp[0][1] = 1;
const int base = (1 << 11) - 1;
for (int i = 1; i <= n; i++) {
for (int s = 0; s <= base; s++)
for (int j = 1; j <= min(10, a[i]); j++) {
int ss = (s | (s << j)) & base;
dp[i][ss] = (1ll * dp[i - 1][s] * qmi(a[i], mod - 2) % mod + dp[i][ss]) % mod;
}
if (a[i] > 10)
for(int s = 0; s <= base; s ++)
dp[i][s] = (1ll * dp[i - 1][s] * (a[i] - 10) % mod * qmi(a[i], mod - 2) % mod + dp[i][s]) % mod;
}
int ans = 0;
for (int s = 0; s <= base; s++)
if(s & (1 << 10)) ans = (ans + dp[n][s]) % mod;