A. Kitchen Utensils
#include <bits/stdc++.h>
#define debug(a) cout << "debug : " << (#a)<< " = " << a << endl
using namespace std;
typedef pair<int,int> pii;
typedef long long ll;
const int N = 100 + 10;
const int P = 1e9 + 7;
const int INF = 0x3f3f3f3f;
int n,k,x,a[N];
void solve(){
int cnt = 0, ans = 0;
for(int i = 1; i < N; ++ i){
cnt += (a[i] != 0);
ans = max(ans,a[i]);
}
ans = (ans + k - 1) / k * k;
printf("%d\n", cnt * ans - n);
}
int main(){
scanf("%d%d", &n, &k);
for(int i = 1; i <= n; ++ i){
scanf("%d", &x);
++ a[x];
}
solve();
return 0;
}
B. Personalized Cup
-
题意 给定一个字符串,你需要将其分成一个矩形,使得行
≤
5
\leq 5
≤5,列
≤
20
\leq 20
≤20。你可以补充任意的* 字符,但必须满足相邻两行的* 字符数量相差
≤
1
\leq 1
≤1。请你构造出这样的矩形。 -
解题思路 我们可以枚举行,从而可以确定列。那么怎么确定行列才可行呢?必然是使得需要添加的* 最小最优,所以我们选择能填充的最小矩形,即
l
e
n
/
n
+
(
l
e
n
%
n
!
=
0
)
len / n+(len \% n != 0)
len/n+(len%n!=0)。那么易知,其数量不会超过行数,所以如果有我们则可以每行填一个即可。 -
AC代码
#include <bits/stdc++.h>
#define debug(a) cout << "debug : " << (#a)<< " = " << a << endl
using namespace std;
typedef pair<int,int> pii;
typedef long long ll;
const int N = 1e5 + 10;
const int P = 1e9 + 7;
const int INF = 0x3f3f3f3f;
int n,m,len;
char s[N];
void solve(){
len = strlen(s + 1);
for(n = 1; n <= 5; ++ n){
m = len / n + (len % n != 0);
if(n <= 5 && m <= 20)break;
}
int cnt = n * m - len, idx = 1;
printf("%d %d\n", n, m);
for(int i = 1; i <= n; ++ i){
for(int j = 1; j <= m - (cnt != 0); ++ j){
printf("%c", s[idx ++]);
}
if(cnt){
printf("*");
-- cnt;
}
puts("");
}
}
int main(){
scanf("%s", s + 1);
solve();
return 0;
}
C. Playing Piano
-
题意 给你一个
a
a
a序列,需要你构造出一个
b
b
b序列,使得:如果
a
i
<
a
i
+
1
,
则
b
i
<
b
i
+
1
a_i < a_{i + 1},则b_i < b_{i + 1}
ai?<ai+1?,则bi?<bi+1?;如果
a
i
>
a
i
+
1
,
则
b
i
>
b
i
+
1
a_i > a_{i + 1},则b_i > b_{i + 1}
ai?>ai+1?,则bi?>bi+1?;如果
a
i
=
a
i
+
1
,
则
b
i
!
=
b
i
+
1
a_i = a_{i + 1},则b_i != b_{i + 1}
ai?=ai+1?,则bi?!=bi+1?。
b
i
b_i
bi?取值范围为
[
1
,
5
]
[1,5]
[1,5]。 -
解题思路 观察此题易知,当前构造的
b
i
b_i
bi?只与
b
i
?
1
b_{i-1}
bi?1?的值有关系,即由
b
i
?
1
b_{i-1}
bi?1?转移过来的。所以这个过程我们是可以通过
d
p
dp
dp实现的,但我们无需考虑最优解,只是状态的转移计算而已。 我们可以用
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]表示前
i
i
i个且第
i
i
i个填
j
j
j的合法情况。为
0
0
0代表不可行,否则可行。 据此题易解。注意路径的记录,我们可以用
p
r
e
[
i
]
[
j
]
pre[i][j]
pre[i][j]表示状态为
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]的前一个状态取的值。 -
AC代码
#include <bits/stdc++.h>
#define debug(a) cout << "debug : " << (#a)<< " = " << a << endl
using namespace std;
typedef pair<int,int> pii;
typedef long long ll;
const int N = 1e5 + 10;
const int P = 1e9 + 7;
const int INF = 0x3f3f3f3f;
int n,a[N];
bool dp[N][10];
int pre[N][10];
int Stack[N],top;
void solve(){
for(int j = 1; j <= 5; ++ j){
dp[1][j] = 1;
}
for(int i = 2; i <= n; ++ i){
for(int j = 1; j <= 5; ++ j){
if(dp[i - 1][j]){
if(a[i] > a[i - 1]){
for(int k = j + 1; k <= 5; ++ k){
dp[i][k] = true, pre[i][k] = j;
}
}
else if(a[i] == a[i - 1]){
for(int k = 1; k <= 5; ++ k){
if(k != j){
dp[i][k] = true, pre[i][k] = j;
}
}
}
else{
for(int k = 1; k < j; ++ k){
dp[i][k] = true, pre[i][k] = j;
}
}
}
}
}
int x = -1;
for(int j = 1; j <= 5; ++ j){
if(dp[n][j]) x = j;
}
if(x == -1){
puts("-1");
}
else{
top = 0;
for(int i = n; i >= 1; -- i){
Stack[top ++] = x;
x = pre[i][x];
}
for(int i = top - 1; i >= 0; -- i){
printf("%d ", Stack[i]);
}
puts("");
}
}
int main(){
scanf("%d", &n);
for(int i = 1; i <= n; ++ i){
scanf("%d", &a[i]);
}
solve();
return 0;
}
D. Barcelonian Distance
-
题意 给你一条直线
a
x
+
b
y
+
c
=
0
ax+by+c=0
ax+by+c=0、起点坐标和终点坐标。你可以沿着坐标轴方向行走,在直线上你也可以沿着直线走。问从起点到终点的最短距离。 -
解题思路 当不通过直线的时候,最短距离就是曼哈顿距离。而如果通过直线,意味着我们可以走斜线,在直线上自然只有一种方式,但我们如果到达直线,如果从直线上到达终点,这里要分四种情况:起点从从y轴到达直线上或从x轴到达直线上。终点同理。我们求出在直线上的两个坐标即可。 注意特判,当a为0或者b为0的时候,此时就是一条直线,就是曼哈顿距离。 -
AC代码
#include <bits/stdc++.h>
#define debug(a) cout << "debug : " << (#a)<< " = " << a << endl
#define x first
#define y second
using namespace std;
typedef pair<double,double> pdd;
typedef long long ll;
const int N = 1e5 + 10;
const int P = 1e9 + 7;
const int INF = 0x3f3f3f3f;
double a,b,c;
pdd st,ed;
double getDist1(pdd a, pdd b){
return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}
double getDist2(pdd a, pdd b){
return abs(a.x - b.x) + abs(a.y - b.y);
}
void solve(){
double minn = getDist2(st,ed),ans;
if(a != 0 && b != 0){
pdd new_st(st.x,(-1) * (a * st.x + c) / b), new_ed(ed.x,(-1) * (a * ed.x + c) / b);
ans = getDist1(new_st, new_ed) + getDist1(st, new_st) + getDist1(ed, new_ed);
minn = min(ans, minn);
new_st = pdd(st.x,(-1) * (a * st.x + c) / b), new_ed = pdd((-1) * (b * ed.y + c) / a, ed.y);
ans = getDist1(new_st, new_ed) + getDist1(st, new_st) + getDist1(ed, new_ed);
minn = min(ans, minn);
new_st = pdd((-1) * (b * st.y + c) / a, st.y), new_ed = pdd(ed.x, (-1) * (a * ed.x + c) / b);
ans = getDist1(new_st, new_ed) + getDist1(st, new_st) + getDist1(ed, new_ed);
minn = min(ans, minn);
new_st = pdd((-1) * (b * st.y + c) / a, st.y), new_ed = pdd((-1) * (b * ed.y + c) / a, ed.y);
ans = getDist1(new_st, new_ed) + getDist1(st, new_st) + getDist1(ed, new_ed);
minn = min(ans, minn);
}
printf("%.8lf\n", minn);
}
int main(){
scanf("%lf%lf%lf", &a, &b, &c);
scanf("%lf%lf%lf%lf", &st.x, &st.y, &ed.x, &ed.y);
solve();
return 0;
}
E. The Unbearable Lightness of Weights
-
题意 有
n
n
n个砝码,你不知道每个砝码多重,你只知道它们有
a
1
,
a
2
,
a
3
…
a
n
a_1,a_2,a_3\dots a_n
a1?,a2?,a3?…an?。但是你的朋友知道,你可以每次拿出
k
k
k个砝码给你的朋友,他会告诉你
k
k
k个砝码的重量和,经过
1
1
1次尝试之后,你最多可以区分出多少个砝码? -
解题思路 首先我们需要清楚的一件事就是我们选取砝码一定是选取砝码重量相同且砝码重量总和唯一的,这样才能保证我们唯一确定且知晓每个砝码多重。所以我们即是判定砝码重量总和唯一且砝码数量最多的是哪个?我们则可以先处理出砝码的重量种类以及对应数量。 这题很类似求
i
i
i个物品体积为
j
j
j的方案数,即分组背包问题。我们可以用
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]来表示前
i
i
i个物品且体积为
j
j
j的方案数,若方案数唯一则可行。 据此进行状态转移即可。 注意特判砝码种类只有两个的情况,因为这我们只需要挑出最大的那个且值相同的组合,这样确定了该组,另一组也唯一确定了。 -
AC代码
#include <bits/stdc++.h>
#define debug(a) cout << "debug : " << (#a)<< " = " << a << endl
using namespace std;
typedef pair<int,int> pii;
typedef long long ll;
const int N = 1e4 + 10;
const int P = 1e9 + 7;
const int INF = 0x3f3f3f3f;
int n,x,cnt[N],dp[105][N];
vector<pii> v;
void solve(){
for(int i = 1; i <= 100; ++ i){
if(cnt[i])v.push_back({i, cnt[i]});
}
dp[0][0] = 1;
for(auto iter : v){
int w = iter.first, num = iter.second;
for(int j = N - 1; j > 0; -- j){
for(int i = 1; i <= n; ++ i){
for(int k = 1; k <= num && k * w <= j && k <= i; ++ k){
dp[i][j] += dp[i - k][j - k * w];
}
}
}
}
if(v.size() == 2){
printf("%d\n", n);
}
else{
int ans = 1;
for(auto iter : v){
int w = iter.first, num = iter.second;
for(int i = 1; i <= num; ++ i){
if(dp[i][i * w] == 1){
ans = max(ans, i);
}
}
}
printf("%d\n", ans);
}
}
int main(){
scanf("%d", &n);
for(int i = 1; i <= n; ++ i){
scanf("%d", &x);
++ cnt[x];
}
solve();
return 0;
}
|