I - Ivan and the swimming pool
题目链接
题意:
给你高度图,让你选择一个联通区域,要求面积至少为S,连通区域的高度取决于最低高度,求可能的最高高度
思路:
竟然没想到二分直接寄 二分高度BFS判断就行,以后做题思维要敏锐
代码:
#include <bits/stdc++.h>
#define fi first
#define se second
#define pb push_back
#define pf push_front
#define endl '\n'
//#define int long long
#define bug(x) cout << #x << ":" << x << endl;
using namespace std;
typedef pair<int, int> PII;
typedef long long ll;
const int INF = 0x3f3f3f3f, mod = 1e9 + 7;
const int N = 1e6 + 10;
vector<int> v[N];
vector<int> st[N];
map<PII, int> mp;
int k, n, m;
int dx[] = {0, 0, -1, 1}, dy[] = {-1, 1, 0, 0};
int bfs(int sx, int sy, int depth){
queue<PII> q;
q.push({sx, sy});
st[sx][sy] ++;
int ans = 1;
while (q.size()){
auto t = q.front();
q.pop();
for (int i = 0; i < 4; i ++){
int x = t.fi + dx[i], y = t.se + dy[i];
if (x < 0 || x >= n || y < 0 || y >= m) continue;
if (v[x][y] < depth || st[x][y]) continue;
st[x][y] ++;
ans ++;
q.push({x, y});
}
}
return ans;
}
bool check(int x){// 判断是否能找到面积大于等于k的且深度为x的连通块
for (int i = 0; i < n; i ++){
for (int j = 0; j < m; j ++){
st[i][j] = 0;
}
}
int ans = 0;
for (int i = 0; i < n; i ++){
for (int j = 0; j < m; j ++){
if (v[i][j] >= x && !st[i][j]){
ans = max(ans, bfs(i, j, x));
}
}
}
return ans >= k;
}
void solve(){
scanf("%d %d %d", &k, &n, &m);
for (int i = 0; i < n; i ++){
for (int j = 0; j < m; j ++){
int x;
scanf("%d", &x);
v[i].pb(x);
st[i].pb(0);
}
}
int l = 0, r = 1e9;
while (l < r){
int mid = l + r + 1 >> 1;
if (check(mid)) l = mid;
else r = mid - 1;
}
printf("%d", l);
}
signed main(){
//ios::sync_with_stdio(false);
//cin.tie(0), cout.tie(0);
int T = 1;
while (T --){
solve();
}
return 0;
}
J - Jingle Bells
思路:
树形 + 状压 dp,一开始以为挺简单,但要注意的细节很多
详细题解
代码:
#include <bits/stdc++.h>
#define fi first
#define se second
#define pb push_back
#define pf push_front
#define endl '\n'
#define int long long
#define bug(x) cout << #x << ":" << x << endl;
using namespace std;
typedef pair<int, int> PII;
typedef long long ll;
const int INF = 0x3f3f3f3f, mod = 1e9 + 7;
const int N = 2e5 + 10;
int n;
int h[N], e[N], ne[N], w[N], idx;
int dp[N][35];
void add(int a, int b, int c){
e[idx] = b;
w[idx] = c;
ne[idx] = h[a];
h[a] = idx ++;
}
void dfs(int u, int fa){
dp[u][0] = 1;// 什么都不染方案数为1
for (int i = h[u]; i != -1; i = ne[i]){
int v = e[i];
if (v == fa) continue;
int l = 0, r = 4; //5种颜色
if (w[i]) l = r = w[i] - 1; //假设这条边本身有色就为自己
dfs(v, u);
for (int state = (1 << 5) - 1; state >= 0; state --){ //父节点状态
for (int c = l; c <= r; c ++){ //当前边的颜色
if (state & (1 << c)) continue;// 如果颜色与父节点相同
for (int son = 0; son < (1 << 5); son ++){ //子节点状态
if (son & (1 << c)) continue;// 如果颜色与子节点相同
dp[u][state | (1 << c)] += dp[u][state] * dp[v][son] % mod;
dp[u][state | (1 << c)] %= mod;
}
}
dp[u][state] = 0;
}
}
}
void solve(){
cin >> n;
memset(h, -1, sizeof(h));
for (int i = 0; i < n - 1; i ++){
int a, b, c;
cin >> a >> b >> c;
add(a, b, c);
add(b, a, c);
}
dfs(1, -1);
int ans = 0;
for (int i = 0; i < (1 << 5); i ++)
ans = (ans + dp[1][i]) % mod;
cout << ans << endl;
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int T = 1;
while (T --){
solve();
}
return 0;
}