A.Pokemon Master
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
template <typename T>
inline void rd(T& x)
{
ll tmp = 1; char c = getchar(); x = 0;
while (c > '9' || c < '0') {
if (c == '-')tmp = -1; c = getchar(); }
while (c >= '0' && c <= '9') {
x = x * 10 + c - '0'; c = getchar(); }
x *= tmp;
}
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const int N = 1e5 + 10;
const int M = 1e7 + 10;
const double eps = 1e-8;
int main() {
ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
//FILE* _INPUT = freopen("input.txt", "r", stdin);
//FILE* _OUTPUT = freopen("output.txt", "w", stdout);
int T; rd(T);
while (T--) {
int n, m; rd(n), rd(m);
ll suml=0,sumr=0;
for (int i = 1; i <= n; ++i) {
ll tmp; rd(tmp);
suml+=tmp;
}
for (int i = 1; i <= m; ++i) {
ll tmp; rd(tmp);
sumr+=tmp;
}
if (suml > sumr) puts("Calem");
else if (suml == sumr) puts("Draw");
else puts("Serena");
}
return 0;
}
B.Problem Arrangement
传送门
状压dp,这里将12个问题进行二进制压缩,该位为0表示尚未解决,1表示已经解决;
- 用状态压缩的性质枚举 0 − 2 n − 1 0-2^{n-1} 0−2n−1 个状态
- 由于点数M只有500,考虑暴力枚举点数M
- 那么状态方程就容易推出来了,具体详情见代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
template <typename T>
inline void rd(T& x)
{
ll tmp = 1; char c = getchar(); x = 0;
while (c > '9' || c < '0') {
if (c == '-')tmp = -1; c = getchar(); }
while (c >= '0' && c <= '9') {
x = x * 10 + c - '0'; c = getchar(); }
x *= tmp;
}
const int inf = 0x3f3f3f3f;
const int mod = 7;
const int N = (1 << 13) + 10;
const int M = 1e7 + 10;
const double eps = 1e-8;
ll dp[N][510];
int a[13][13];
ll gcd(ll x, ll y) {
if (y == 0) return x;
return gcd(y, x % y);
}
int main() {
ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
// FILE* _INPUT = freopen("input.txt", "r", stdin);
// FILE* _OUTPUT = freopen("output.txt", "w", stdout);
int T; rd(T);
while (T--) {
memset(dp, 0, sizeof dp);
int n, m; rd(n), rd(m);
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) rd(a[i][j]);
}
dp[0][0] = 1;
for (int i = 0; i < (1 << n); ++i) {
int cnt = 0;
for (int j = 0; j < n; ++j) {
if (i & (1 << j)) ++cnt;
}
for (int j = 0; j < n; ++j) {
if (i & (1 << j)) continue;
for (int k = 0; k <= m; ++k) {
int tmp = k + a[j][cnt];
if (tmp >= m) {
dp[i ^ (1 << j)][m] += dp[i][k];
}
else dp[i ^ (1 << j)][tmp] += dp[i][k];
}
}
}
if (dp[(1 << n) - 1][m] == 0) puts("No solution");
else {
ll ans = 1;
for (int i = 1; i <= n; ++i) ans = ans * i;
ll tmp = gcd(ans, dp[(1 << n) - 1][m]);
printf("%lld/%lld\n", ans / tmp, dp[(1 << n) - 1][m] / tmp);
}
}
return 0;
}
C.Talented Chef
- 需要在最短时间内烹饪完成,显然需要逐步的平摊时间,这个就是所需的平均时间向上取整
- 但是还要考虑一点,当一条鱼的烹饪时间很长的时候,甚至是多于平均时间的时候,这时候就需要取较大的一项,即这条鱼的单个烹饪时间
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
template <typename T>
inline void rd(T& x)
{
ll tmp = 1; char c = getchar(); x = 0;
while (c > '9' || c < '0') {
if (c == '-')tmp = -1; c = getchar(); }
while (c >= '0' && c <= '9') {
x = x * 10 + c - '0'; c = getchar(); }
x *= tmp;
}
const int inf = 0x3f3f3f3f;
const int mod = 7;
const int N = 1e5 + 10;
const int M = 1e7 + 10;
const double eps = 1e-8;
int main() {
ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
// FILE* _INPUT = freopen("input.txt", "r", stdin);
// FILE* _OUTPUT = freopen("output.txt", "w", stdout);
int T; rd(T);
while (T--) {
int n, m; rd(n), rd(m);
ll sum = 0; ll maxn = 0;
for (int i = 1; i <= n; ++i) {
int tmp; rd(tmp);
sum += tmp;
maxn = max(maxn, 1LL*tmp);
}
ll ans = sum / m;
if (sum % m) ++ans;
printf("%lld\n", max(ans,maxn));
}
return 0;
}
E.Paint the Grid Again
- 题意是刷墙有个规则,横向只能刷黑色,纵向只能刷白色,那么问题就好解决了
- 现在只看每一行,按照规则本应该一行都是黑色的,若出现了白色,则说明先横向刷黑色,再纵向刷那一列的白色,即 R [ i ] − > C [ j ] , 设 该 点 坐 标 为 ( i , j ) R[i]->C[j],设该点坐标为(i,j) R[i]−>C[j],设该点坐标为(i,j)
- 同样只看每一列 ,若一列中出现黑色的,则说明 C [ j ] − > R [ i ] C[j]->R[i] C[j]−>R[i]
- 根据上述规则,进行建边,然后跑一遍拓扑序即可
- 但答案需要输出最小字典序,首先列 C C C字典序 < R <R <R;数字则从小到大排,所以建边的时候,将列建边为 j ∈ [ 1 , n ] j\in[1,n] j∈[1,n],将行建边为 i ∈ [ n + 1 , 2 × n ] i\in[n+1,2×n] i∈[n+1,2×n]
- 最后在进行拓扑序的时候将点放进优先队列里,数字小的先出队列即可
- 判断没有解决方案是先标记所有进行粉刷过的行和列,然后在拓扑序的时候进行新一轮标记,若有粉刷过的行或者列没有出现在拓扑序中,则没有解决方法,类似形成了一个环
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
template <typename T>
inline void rd(T& x)
{
ll tmp = 1; char c = getchar(); x = 0;
while (c > '9' || c < '0') {
if (c == '-')tmp = -1; c = getchar(); }
while (c >= '0' && c <= '9') {
x = x * 10 + c - '0'; c = getchar(); }
x *= tmp;
}
const int inf = 0x3f3f3f3f;
const int mod = 7;
const int N = 1e3 + 10;
const int M = 1e7 + 10;
const double eps = 1e-8;
int head[N], cnt;
struct edge {
int next, to;
}e[M];
void add(int u, int v) {
e[cnt].next = head[u];
e[cnt].to = v;
head[u] = cnt++;
}
char mp[505][505];
int degree[N];
bool row[505], col[505], vis[N];
vector<int>ans;
bool check(int n) {
memset(vis, false, sizeof vis);
priority_queue<int,vector<int>,greater<int> >que;
for (int i = 1; i <= n; ++i) {
if (col[i] && !degree[i]) {
que.push(i);
}
}
for (int i = 1; i <= n; ++i) {
if (row[i] && !degree[i+n]) {
que.push(i+n);
}
}
if (que.empty()) return 0;
while (!que.empty()) {
int u = que.top(); que.pop();
vis[u] = true;
if (u > n) {
ans.push_back(u);
vis[u] = true;
}
else {
ans.push_back(u);
vis[u] = true;
}
for (int i = head[u]; ~i; i = e[i].next) {
int v = e[i].to;
if (!(--degree[v])) {
que.push(v);
}
}
}
for (int i = 1; i <= n; ++i) {
if (col[i]&&!vis[i]) return false;
}
for (int i = n + 1; i <= 2 * n; ++i) {
if (row[i - n] && !vis[i]) return false;
}
for (int i = 0; i < ans.size(); ++i) {
if (ans[i] > n) {
printf("R%d", ans[i] - n);
}
else printf("C%d", ans[i]);
printf("%s", i == ans.size() - 1 ? "\n" : " ");
}
return 1;
}
int main() {
ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
//FILE* _INPUT = freopen("input.txt", "r", stdin);
//FILE* _OUTPUT = freopen("output.txt", "w", stdout);
int T; rd(T);
while (T--) {
int n; rd(n);
memset(head, -1, sizeof head); cnt = 0;
memset(row, false, sizeof row);
memset(col, false, sizeof col);
memset(degree, 0, sizeof degree);
ans.clear();
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= n; ++j) {
scanf(" %c", &mp[i][j]);
if (mp[i][j] == 'X') row[i] = true;
else if (mp[i][j] == 'O') col[j] = true;
}
}
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= n; ++j) {
if (row[i]&&mp[i][j] == 'O') {
add(i + n, j);
++degree[j];
}
}
}
for (int j = 1; j <= n; ++j) {
for (int i = 1; i <= n; ++i) {
if (col[j]&&mp[i][j] == 'X') {
add(j, i + n);
++degree[i + n];
}
}
}
if (!check(n)) puts("No solution");
}
return 0;
}
F.Paint the Grid Reloaded
传送门
题意:
- 一个块上下左右相通的地方的颜色相同的即可以形成联通块
- 然后一个联通块附近必定是与他颜色相反的联通块
- 所以一个联通块反转颜色,就必定与附近的联通块连接在一起,然后再反转…
- 所以这一题首先要对图进行缩点,然后枚举起点进行bfs来确定反转次数,求其中的最小反转次数
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
template <typename T>
inline void rd(T& x)
{
ll tmp = 1; char c = getchar(); x = 0;
while (c > '9' || c < '0') {
if (c == '-')tmp = -1; c = getchar(); }
while (c >= '0' && c <= '9') {
x = x * 10 + c - '0'; c = getchar(); }
x *= tmp;
}
const int inf = 0x3f3f3f3f;
const int mod = 7;
const int N = 1e4 + 10;
const int M = 1e7 + 10;
const double eps = 1e-8;
int n, m;
char mp[55][55];
bool vis[55][55];
int num[55][55];
int dir[][2] = {
1,0,-1,0,0,1,0,-1 }, cnt;
void bfs(int x,int y) {
queue<pii>que;
que.push({
x,y });
stack<pii>stk;
while (!que.empty()) {
pii p = que.front(); que.pop();
stk.push(p);
if (vis[p.first][p.second]) continue;
vis[p.first][p.second] = 1;
for (int i = 0; i < 4; ++i) {
int xx = p.first + dir[i][0], yy = p.second + dir[i][1];
if (xx <= 0 || xx > n || yy <= 0 || yy > m || vis[xx][yy] || mp[xx][yy] != mp[p.first][p.second]) continue;
que.push({
xx,yy });
}
}
++cnt;
while (!stk.empty()) {
pii p = stk.top(); stk.pop();
num[p.first][p.second] = cnt;
}
}
int head[N], cntE;
struct edge {
int next, to;
}e[M];
void add(int u, int v) {
e[cntE].to = v;
e[cntE].next = head[u];
head[u] = cntE++;
}
bool mark[N];
int bfs(int x) {
queue<pii>que;
que.push({
x,1 });
int ans = 0;
while (!que.empty()) {
pii p = que.front(); que.pop();
int u = p.first;
if (mark[u]) continue;
mark[u] = true;
ans = max(ans, p.second);
for (int i = head[u]; ~i; i = e[i].next) {
int v = e[i].to;
if (mark[v]) continue;
que.push({
v,p.second + 1 });
}
}
return ans-1;
}
int solve() {
memset(vis, false, sizeof vis); cnt = 0;
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= m; ++j) {
if (vis[i][j]) continue;
bfs(i, j);
}
}
memset(head, -1, sizeof head); cntE = 0;
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= m; ++j) {
for (int k = 0; k < 4; ++k) {
int x = i + dir[k][0], y = j + dir[k][1];
if (x <= 0 || x > n || y <= 0 || y > m) continue;
if (num[x][y] != num[i][j]) add(num[i][j], num[x][y]);
}
}
}
int minn = inf;
for (int i = 1; i <= cnt; ++i) {
for (int j = 1; j <= cnt; ++j) mark[j] = false;
minn = min(minn, bfs(i));
}
return minn;
}
int main() {
ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
// FILE* _INPUT = freopen("input.txt", "r", stdin);
// FILE* _OUTPUT = freopen("output.txt", "w", stdout);
int T; rd(T);
while (T--) {
rd(n), rd(m);
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= m; ++j) {
scanf(" %c", &mp[i][j]);
}
}
printf("%d\n", solve());
}
return 0;
}
G.Ternary Calculation
传送门
水题,只有三个数字的运算,直接枚举运算可能性的话也就只有25种
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
template <typename T>
inline void rd(T& x)
{
ll tmp = 1; char c = getchar(); x = 0;
while (c > '9' || c < '0') {
if (c == '-')tmp = -1; c = getchar(); }
while (c >= '0' && c <= '9') {
x = x * 10 + c - '0'; c = getchar(); }
x *= tmp;
}
const int inf = 0x3f3f3f3f;
const int mod = 7;
const int N = 1e5 + 10;
const int M = 1e7 + 10;
const double eps = 1e-8;
char s[N];
int main() {
ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
// FILE* _INPUT = freopen("input.txt", "r", stdin);
// FILE* _OUTPUT = freopen("output.txt", "w", stdout);
int T; rd(T);
while (T--) {
int a[5]; char b[5];
scanf("%d %c %d %c %d", &a[1], &b[1], &a[2], &b[2], &a[3]);
if (b[1] == '-' && (b[2] == '-' || b[2] == '+')) {
if (b[2] == '+') printf("%d\n", a[1] - a[2] + a[3]);
else printf("%d\n", a[1] - a[2] - a[3]);
continue;
}
if (b[1] == '+'||b[1]=='-') {
int ans;
if (b[2] == '+') ans = a[2] + a[3];
else if (b[2] == '-') ans = a[2] - a[3];
else if (b[2] == '*') ans = a[2] * a[3];
else if (b[2] == '/') ans = a[2] / a[3];
else ans = a[2] % a[3];
if (b[1] == '+') printf("%d\n", a[1] + ans);
else printf("%d\n", a[1] - ans);
}
else {
int ans;
if (b[1] == '*') ans = a[1] * a[2];
else if (b[1] == '/') ans = a[1] / a[2];
else ans = a[1] % a[2];
if (b[2] == '+') ans = ans + a[3];
else if (b[2] == '-') ans = ans - a[3];
else if (b[2] == '*') ans = ans * a[3];
else if (b[2] == '/') ans = ans / a[3];
else ans = ans % a[3];
printf("%d\n", ans);
}
}
return 0;
}
J.What day is that day?
传送门
这题可以打表找规律,也可以用取模的原理,发现刚好是一个等比数列求和
L.Access System
[传送门](Access System)
将所有时间换算成秒存起来后排序即可
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
template <typename T>
inline void rd(T& x)
{
ll tmp = 1; char c = getchar(); x = 0;
while (c > '9' || c < '0') {
if (c == '-')tmp = -1; c = getchar(); }
while (c >= '0' && c <= '9') {
x = x * 10 + c - '0'; c = getchar(); }
x *= tmp;
}
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const int N = 1e5 + 10;
const int M = 1e7 + 10;
const double eps = 1e-8;
struct node {
int id, num;
bool friend operator<(const node& a, const node& b) {
if (a.num == b.num) return a.id < b.id;
return a.num < b.num;
}
}a[N];
vector<int>ans;
int main() {
ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
//FILE* _INPUT = freopen("input.txt", "r", stdin);
//FILE* _OUTPUT = freopen("output.txt", "w", stdout);
int T; rd(T);
while (T--) {
int n, l; rd(n), rd(l);
ans.clear();
for (int i = 1; i <= n; ++i) {
int x, y, z;
scanf("%d:%d:%d", &x, &y, &z);
a[i].num = x * 3600 + y * 60 + z;
a[i].id = i;
}
sort(a + 1, a + 1 + n);
ans.push_back(a[1].id);
int now = a[1].num + l;
for (int i = 2; i <= n; ++i) {
if (a[i].num < now) continue;
ans.push_back(a[i].id);
now = a[i].num + l;
}
sort(ans.begin(), ans.end());
printf("%d\n%d", ans.size(),ans[0]);
for (int i = 1; i < ans.size();++i) {
printf(" %d", ans[i]);
}
puts("");
}
return 0;
}