[ABC310] D~F 题解

发布时间 2023-08-06 19:14:54作者: MoyouSayuki

[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;