A
题目
\(M \le 10\), 考虑状压 DP
可以发现, 一个数字 \(x\) 可不可以填取决于最后一个 \(x\) 后有没有填 \(X_x\)
状态 \((i, s, sum)\) 表示填了前 \(i\) 个数字, 可以填的子集为 \(s\) 时的方案数 \(sum\)
转移, 枚举当前选 \(x\), 首先不能再选 \(x\), 之后所有的 \(X_i = x\) 的 \(i\) 都能选
/*
cnt[x_B] > cnt[B]
*/#include<bits/stdc++.h>using namespace std;const int N = 1e4 + 5, mod = 998244353;int ans, m, n, t, x, dp[N][(1 << 12)];
vector<int>g[20];int main(){cin >> m >> n;for(int i = 0; i < m; ++i){cin >> x;x--;g[x].push_back(i);}dp[0][(1 << m) - 1] = 1;for(int i = 0; i < n; ++i){for(int s = 0; s < (1 << m); ++s){for(int j = 0; j < m; ++j){if(s & (1 << j)){t = (s ^ (1 << j));for(auto v : g[j]){t |= (1 << v);}dp[i + 1][t] = (dp[i][s] + dp[i + 1][t]) % mod;}}}}for(int i = 0; i < (1 << m); i++){ans = (ans + dp[n][i]) % mod;}cout << ans;return 0;
}
时间复杂度 \(O(nm2^m)\)
空间复杂度 \(O(n2^m)\)
C
题目
对于一个把红色改成紫色, 只对蓝色有影响
对于一个把蓝色改成紫色, 只对红色有影响
所有改成紫色时相互独立的
跑两遍 dij
就可以
#include<bits/stdc++.h>using namespace std;const int N = 505, dx[] = {0, 0, 1, -1}, dy[] = {1, -1, 0, 0};struct Node{int x, y, d;
};struct cmp{bool operator()(const Node &i, const Node &j){return i.d > j.d;}
};priority_queue<Node, vector<Node>, cmp>pq;
int n, a[N][N], dist[4][N][N], vis[4][N][N];
char c;void C(int x, int y, int id, int s){if(x < 1 || y < 1 || x > n || y > n || dist[id][x][y] <= s){return;}s += (a[x][y] != id);dist[id][x][y] = s;pq.push({x, y, s});
}void bfs(int sx, int sy, int id){for(int i = 1; i <= n; ++i){for(int j = 1; j <= n; ++j){dist[id][i][j] = 1e9;}}C(sx, sy, id, 0);while(pq.size()){auto [x, y, d] = pq.top();pq.pop();if(vis[id][x][y]){continue;}vis[id][x][y] = 1;for(int i = 0; i < 4; ++i){C(x + dx[i], y + dy[i], id, d);}}
}int main(){cin >> n;for(int i = 1; i <= n; ++i){for(int j = 1; j <= n; ++j){cin >> c;a[i][j] = c == 'R';}}bfs(1, 1, 1);bfs(n, 1, 0);cout << dist[1][n][n] + dist[0][1][n];return 0;
}
时间复杂度 \(O(n^2 log_2 n)\)
空间复杂度 \(O(n^2)\)
D
题目
令 \(sum_i\) 为前缀 xor
写出DP
暴力转移式 dp[i] += dp[j] * (sum[i] ^ sum[j])
。
对于 \(sum_i\) 的二进制, 做一遍前缀和
#include<bits/stdc++.h>using namespace std;const int N = 3e5 + 5, mod = 1e9 + 7;long long a[N], sum[N], e[N][100];
int n, dp[N];int main(){cin >> n;for(int i = 1; i <= n; ++i){cin >> a[i];sum[i] = sum[i - 1] ^ a[i];}dp[0] = 1;for(int i = 0; i < 63; ++i){e[i][0] = 1;}for(int i = 1; i <= n; ++i){for(int k = 0; k < 63; ++k){if(sum[i] & (1ll << k)){dp[i] = (dp[i] + 1ll * e[k][0] * ((1ll << k) % mod) % mod) % mod;}else{dp[i] = (dp[i] + 1ll * e[k][1] * ((1ll << k) % mod) % mod) % mod;}}for(int k = 0; k < 63; ++k){if(sum[i] & (1ll << k)){e[k][1] = (e[k][1] + dp[i]) % mod;}else{e[k][0] = (e[k][0] + dp[i]) % mod;}}}cout << dp[n];return 0;
}
时间复杂度 \(O(n \log_2 V)\)
空间复杂度 \(O(n)\)