题意:给你一个方形图案,给一系列右旋转或者左旋转操作,要求输出操作后的图案
思路:因为最多只有右旋90,180,270度这三种,我们处理完所有的操作后模拟旋转就行。
#include<bits/stdc++.h>
#define ll long long
#define pb push_back
using namespace std;
const int maxn = 1005;
char s[maxn][maxn], str[maxn][maxn];
char mv[maxn], lj[40] = {">v<^"};
int n;
void gao(int i, int j, int &x, int &y, int res) {
if (res == 1)
x = j, y = n + 1 -i;
if (res == 2)
x = n + 1 - i, y = n + 1 - j;
}
int main() {
scanf("%d%s", &n, mv + 1);
for (int i = 1; i <= n; i++)
scanf("%s", s[i] + 1);
int res = 0;
for (int i = 1; mv[i]; i++)
if (mv[i] == 'L')
res--;
else
res++;
while (res < 0)
res += 4;
while (res > 4)
res -= 4;
if (res == 0 || res == 4) {
for (int i = 1; i <= n; i++)
printf("%s\n", s[i] + 1);
return 0;
}
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++) {
int x, y;
if (res == 3) {
gao(i, j, x, y, 1);
gao(x, y, x, y, 2);
}
else
gao(i, j, x, y, res);
int p = 0;
char c = '.';
if (s[i][j] == c) {
str[x][y] = '.';
continue;
}
for (;; p++)
if (lj[p] == s[i][j])
break;
p += res;
p %= 4;
c = lj[p];
str[x][y] = c;
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++)
printf("%c", str[i][j]);
puts("");
}
}
B. SpongeBob SquarePants
签到
C. I Don’t Want To Pay For The Late Jar!
签到
D. Ali The Multi-billionaire
待补
E. Optimal Slots
题意:给一个总时间T,再给N个时间,要求选取一些时间ti,使得总和sum不超过T且尽量接近T,如果有多种方案,就输出输入顺序早的方案。
思路:我们设 d[i][j] 为能否从 i 到 N 这些时间段选取一些组成 j ,为1可行,为0不可行,转移方程非常简单,就是个01背包:从大到小枚举 j,d[i][j] |= d[i + 1][j - t[i]],我们找到一个最大的 j,使得d[1][j] = 1,那么答案 sum 就是 j,然后我们依次从小到大枚举 i,如果 d[i + 1][sum - t[i]] = 1,那么我们就选取 ti,并且sum -= ti,如果不等于1,跳过ti继续枚举。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn = 24 * 8;
int d[52][maxn], a[51];
int main() {
int T, n;
for (int i = 1; i <= 51; i++)
d[i][0] = 1;
while (cin>>T && T) {
cin>>n;
for (int i = 1; i<= n; i++) {
cin>>a[i];
for (int j = 1; j <= T; j++)
d[i][j] = 0;
}
for (int j = 1; j <= T; j++)
d[n + 1][j] = 0;
for (int i = n; i; i--) {
for (int j = T; j >= a[i]; j--)
d[i][j] |= d[i + 1][j - a[i]];
for (int j = T; j; j--)
d[i][j] |= d[i + 1][j];
}
int sum = T;
while (!d[1][sum])
sum--;
int ans = sum;
int p = 1;
queue<int> q;
while (sum > 0) {
if (a[p] <= sum) {
if (d[p + 1][sum - a[p]])
q.push(a[p]), sum -= a[p];
}
p++;
}
while (!q.empty()) {
printf("%d ", q.front());
q.pop();
}
printf("%d\n", ans);
}
}
题意:有2*N个士兵站成两排,现在要求上面一排的士兵和下面一排的士兵–配对,要求配对的两个士兵,他们的位置相差不能超过e,而且有K队士兵互相讨厌,不能给他们配对,要求输出配对总方案数。
思路:考虑到 e 最大为4,我们状态压缩记录下面哪些士兵已经匹配了,设d[i][j]为上面匹配到第 i 个士兵,下面 i - e 到 i + e个士兵中未被匹配的集合为 j 的方案数,假设第 i 个士兵的状态为11010,e为2,那么表示下面第 i 个士兵和第 i + 2 士兵未被匹配,然后我们枚举未被匹配的士兵 k,如果上面第 i + 1 个士兵不讨厌士兵 k ,假设 k 为 i,那么转移方程:d[i + 1][11100] += d[i][11010],或许你好奇,i + 1 的状态为啥不是 11110,其实到了第 i + 1 个人,他记录的状态是从 i - e + 1开始的,同理,如果 k 为 i + 2,转移方程:d[i + 1][10110] += d[i][11010],此为第 i +1 士兵还可以选择下面 i +1 + e个士兵,如果他们不互相讨厌:d[i + 1][10101] += d[i][11010]。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn = 2010, mod = 1e9 + 7;
ll d[maxn][1<<11];
int ban[maxn][maxn];
void add(ll &x, ll y) {
x += y;
if (x >= mod)
x -= mod;
}
int main() {
int n, e, k, u, v;
cin>>n>>e>>k;
for (int i = 1; i <= k; i++) {
cin>>u>>v;
ban[u][v] = 1;
}
int m = 2 * e + 1;
int s = 1 << m;
d[0][0] = 1;
for (int i = 0; i < n; i++)
for (int j = 0; j < s; j++) {
if (!d[i][j])
continue;
int k1 = max(1, i - e);
int k2 = min(n, i + e + 1);
int s0 = (j << 1);
s0 &= (s - 1);
for (int k = k1; k <= k2; k++) {
int p = m - 1 - (k - (i - e));
if (p == -1)
if (!ban[i + 1][k]) {
add(d[i + 1][s0 | 1], d[i][j]);
continue;
}
if (ban[i + 1][k] || (j & (1 << p)) || p == m - 1)
continue;
add(d[i + 1][s0 | (1 << p + 1)], d[i][j]);
}
}
ll ans = 0;
for (int i = 1; i < s; i++)
add(ans, d[n][i]);
printf("%lld\n", ans);
}
I. To Crash Or Not To Crash
题意:问起点往右走是否能安全通过,如果不能,就输出第一个撞到的障碍物。题目不难,题意难。
J. Kitchen Plates
题意:给5个大小关系,要求按照他们的关系从小到大依次输出。
思路:只有5个可以暴力做,提供一种拓扑排序思路,对于 a < b,那么 b 的度数 ++,并且从 a 到 b 引入一条有向边,最后我们把所有度数为0的点加入队列,枚举他们,假设当前枚举的是 u,枚举 u 连接的点 v,把 v 的度数–,如果v的度数为0,把v加入队列,最后如果还有点度数不为0,那么无解,否则就按照出队顺序输出5个点就行。
#include<bits/stdc++.h>
#define pb push_back
using namespace std;
int d[5];
vector<int> G[5];
int id(char c) {
return c - 'A';
}
int main() {
char c1, c2, c;
for (int i = 1; i <= 5; i++) {
cin>>c1>>c>>c2;
int u = id(c1);
int v = id(c2);
if (c == '>') {
d[u]++;
G[v].pb(u);
}
else {
d[v]++;
G[u].pb(v);
}
}
queue<char>q, q2;
for (int i = 0; i < 5; i++)
if (!d[i])
q.push(i + 'A');
while (!q.empty()) {
int u = q.front() - 'A';
q2.push(u + 'A');
q.pop();
for (auto v : G[u]) {
d[v]--;
if (!d[v])
q.push(v + 'A');
}
}
if (q2.size() != 5)
puts("impossible");
else {
while (!q2.empty())
printf("%c", q2.front()), q2.pop();
}
}
题意:没读懂,但是盲猜题意过了,盲猜:把所有 ti 从小到大排序,开始枚举ti并且记录前缀和sum[i],如果sum[i - 1] <= t[i],那么答案++,并且sum[i] = sum[i - 1] + t[i],否则sum[i] = sum[i - 1]
#include<bits/stdc++.h>
#define ll long long
#define pb push_back
using namespace std;
const int maxn = 1e5 + 10;
int a[maxn];
int main() {
int T, kase = 0;
scanf("%d", &T);
while (T--) {
int n;
scanf("%d", &n);
for (int i = 1; i <= n; i++)
scanf("%d", &a[i]);
sort(a + 1, a + 1 + n);
ll sum = 0, ans = 0;
for (int i = 1; i <= n; i++) {
if (sum <= a[i]) {
sum += a[i];
ans++;
}
}
printf("Case #%d: %lld\n", ++kase, ans);
}
}