补题链接:Here
A - Payment
水题,请问在使用 元钞票的倍数的钱付款以后能找零多少
void solve() {
int n; cin >> n, n %= 1000;
cout << (n == 0 ? 0 : 1000 - n);
}
B - Judge Status Summary
利用 map 的键值特性存值
void solve() {
int n; cin >> n;
string s;
map<string, int>mp;
while (n--) {
cin >> s;
mp[s]++;
}
cout << "AC x " << mp["AC"] << "\n";
cout << "WA x " << mp["WA"] << "\n";
cout << "TLE x " << mp["TLE"] << "\n";
cout << "RE x " << mp["RE"] << "\n";
}
C - H and V
题意:给一个n x m的矩阵,由’#‘和’.’构成,分别代表黑色和白色,现在你可以任选若干行和若干列将其涂成红色,问有多少种涂法使最终只有k个黑色。
因为n和m都是小于等于6的,所以对于一个 的矩阵所有情况也就
种,那就直接爆搜。
爆搜
string g[10];
int ans, cnt;
int h, w, k;
bool vis[10];
void dfs(int r, int c, int sum) {
if (r == h and c == w) {
if (cnt - sum == k)ans++;
return ;
}
int num = 0;
if (r == h) {
for (int i = 0; i < h; ++i)
if (g[i][c] == '#' and (!vis[i]))
num++;
dfs(r, c + 1, sum + num);
dfs(r, c + 1, sum);
} else {
for (int i = 0; i < w; ++i)
if (g[r][i] == '#')num++;
vis[r] = 1;
dfs(r + 1, c, sum + num);
vis[r] = 0;
dfs(r + 1, c, sum);
}
}
void solve() {
cin >> h >> w >> k;
for (int i = 0; i < h; ++i)cin >> g[i];
for (int i = 0; i < h; ++i)
for (int j = 0; j < w; ++j)if (g[i][j] == '#')cnt++;
dfs(0, 0, 0);
cout << ans << "\n";
}
二进制枚举
string s[10];
void solve() {
int h, w, k;
cin >> h >> w >> k;
for (int i = 0; i < h; ++i)cin >> s[i];
int ans = 0;
for (int i = 0; i < (1 << h); ++i)
for (int j = 0; j < (1 << w); ++j) {
int cnt = 0;
for (int ii = 0; ii < h; ++ii)
for (int jj = 0; jj < w; ++jj)
if ((i >> ii & 1) && !(j >> jj & 1))
cnt += s[ii][jj] == '#';
ans += cnt == k;
}
cout << ans << "\n";
}
3道类似的题目
AtCoder Beginner Contest 167 C Skill Up 满足C(n,1),C(n,2),C(n,3),……,C(n,n)的深搜dfs
AtCoder Beginner Contest 165 C Many Requirements 深搜dfs+生成非递减数组
AtCoder Beginner Contest 159 E Dividing Chocolate 二维前缀和+子矩阵和+深搜行+枚举列+注意行边界处理+注意列边界处理
D - Chat in a Circle
现在有一排数字,现在要将这排数字按顺序放入一个圈,每个数字在插入圈时,他的权值就是相邻两个数字中小的那个,第一个插入的人权值为0,问总权值是多少。
既然要让权值最大,那必然要让大的值先插入,否则会被相邻的小的值影响,导致不能贡献权值。以为是一个圈,左右两边都能贡献权值,所以除了最大的数只能贡献一次,剩余的数都可以贡献两次。
using ll = long long;
bool cmp(ll a, ll b) {return a > b;}
void solve() {
int n; cin >> n;
ll sum = 0;
int a[n + 1];
for (int i = 1; i <= n; ++i)cin >> a[i];
sort(a + 1, a + 1 + n, cmp);
sum += a[1];
int idx = 2;
for (int i = 2; i < n; ++i) {
if (i % 2 == 0)sum += a[idx]; // 贡献两次
else sum += a[idx++];
}
cout << sum;
}
F - Intervals on Tree
题意:给你一棵树,节点为1到n,取若干连续编号的节点,求出其连通分量,问所有连续段的连通分量之和。
因为是树,所以一条边必然连接两个连通分量,所以我们可以假设把每个点看成一个连通分量,然后每加入一个边,就把含他的 的数量去掉。
void solve() {
int n; cin >> n;
ll sum = 0;
int l, r;
for (int i = 1; i <= n; ++i)
sum += 1ll * i * (n - i + 1);
for (int i = 1; i < n; ++i) {
cin >> l >> r;
if (l > r)swap(l, r);
sum -= 1ll * l * (n - r + 1);
}
cout << sum;
}