赛氪3.14题解
A,B,M,I是签到题目
(but我B题看走眼,多交了好几发,对我自己无语了
重点是理一下F题的模拟
J题目 奇怪的小鸭子也增加了
题意
有一个A×B 的大澡盆,还有若干个a×b 的长方形小鸭子,澡盆里最少放几只鸭子后,便无法再向其中放入更多的鸭子?
鸭子很倔强,不能旋转成 b×a ,也不能重叠放置。
题解
一开始我以为,小鸭子只能放在线上,实际上不是的
原
来
的
设
想
是
放
在
线
上
,
那
么
一
个
小
鸭
子
可
以
使
得
长
(
(
a
−
1
)
∗
2
+
a
)
,
\color{orange}原来的设想是放在线上,那么一个小鸭子可以使得长((a - 1) * 2 + a),
原来的设想是放在线上,那么一个小鸭子可以使得长((a−1)∗2+a),
宽
(
(
b
−
1
)
∗
2
+
b
)
不
能
放
鸭
子
,
\color{orange}宽((b - 1) * 2+b)不能放鸭子,
宽((b−1)∗2+b)不能放鸭子,
实
际
上
可
以
不
放
在
线
上
,
那
么
就
是
把
一
换
成
精
度
范
围
内
无
限
小
就
好
了
\color{orange}实际上可以不放在线上,那么就是把一换成精度范围内无限小就好了
实际上可以不放在线上,那么就是把一换成精度范围内无限小就好了
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
const int MAX = 2e5 + 10;
const int INF = 1e9;
vector<string> ans;
string res[MAX];
int num[MAX];
const double eps = 1e-12;
int main() {
int A, B, a, b;
scanf("%d%d%d%d", &A, &B, &a, &b);
ll ans = 0;
A -= (a - eps) * 2 + a;
B -= (b - eps) * 2 + b;
ll s = 1, t = 1;
if(A > 0)
s += max(0.0, ((A + (2 * a - 2 * eps))/ (2 * a - eps)));
if(B > 0)
t += max(0.0, ((B + (2 * b - 2 * eps))/ (2 * b - eps)));
ans = s * t;
printf("%lld\n", ans);
}
E题目 神仙爱采药
题意
一个背包体积为V,给出一个字符串s,设长度为n。 则s[i]表示第i天的物品体积,为1或2。第i天可以选择是否将物品i放入背包,若背包容量不够可以先 从中拿出若干物品。 每天结束前在背包中的每个物品会产生一个药丸。 问n天结束后,最多有多少药丸
题解
爆int
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
const int MAX = 2e5 + 10;
const int INF = 1e9;
int num[MAX];
const double eps = 1e-12;
int main() {
int n;
string str;
cin >> n >> str;
ll ans = 0;
int cnt1 = 0, cnt2 = 0;
int tot = 0;
for(int i = 0; i < str.length(); i++) {
if(str[i] == '1') {
if(tot + 1 <= n) {
cnt1++;
tot++;
}
else if(cnt2 >= 1) {
cnt2--;
tot--;
cnt1++;
}
}
else {
if(tot + 2 <= n) {
cnt2++;
tot += 2;
}
}
ans += (cnt1 + cnt2);
}
printf("%lld\n", ans);
}
F 题目 但更爱字符串
题意
您是一个神仙,您尤其喜欢字符串。
定义一个好词是第一个字母大写,其他字母均小写,且长度大于 1 的单词,例如Akworldfinal
、Orzorz
、Orz
、Nb
。
好串是由好词构成的,两个好词之间有且只有一个空格,且一个好串至少有两个好词。如:International Collegiate Programming Contest
。
现在您有一篇文章,想让您将其中的好串进行适当的缩写。如:International Collegiate Programming Contest
改写为ICPC (International Collegiate Programming Contest)
。
注意:好串一定是尽可能长的。如International Collegiate Programming Contest
能且仅能被唯一地缩写成ICPC (International Collegiate Programming Contest)
。
题解
注意点:
可能出现一个单词+逗号+好词==》满足
有可能出现末尾有不止一个标点符号==》可能满足
有可能出现一个单词有两个及其以上大写字母==》不满足
有可能出现一个单词只有一个字母,而且是大写字母==》不满足
有可能出现有不止一个空格的情况==》不满足
(每行不超过 128 个字符,总共不会超过 1000行)
可以o(n^2)
呐呐呐,上面这么多情况,几乎都是我在模拟的时候发现的一个又一个tip,这样频繁修改代码,脑子早就糊掉了,所以,不能直接模拟,可以看一下,基本上是满足o(n^2),就可以枚举判断
下
次
模
拟
多
写
函
数
,
方
便
,
模
拟
题
,
先
看
样
例
(
样
例
提
醒
了
几
个
注
意
点
的
)
\color{red}下次模拟多写函数,方便, 模拟题,先看样例(样例提醒了几个注意点的)
下次模拟多写函数,方便,模拟题,先看样例(样例提醒了几个注意点的)
太
多
边
界
条
件
了
,
下
次
遇
到
这
种
题
目
,
一
定
要
先
多
想
一
想
,
\color{red}太多边界条件了,下次遇到这种题目,一定要先多想一想,
太多边界条件了,下次遇到这种题目,一定要先多想一想,
不
要
上
来
就
写
代
码
,
要
改
出
命
来
,
太
变
态
了
\color{red}不要上来就写代码,要改出命来,太变态了
不要上来就写代码,要改出命来,太变态了
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
const int MAX = 2e5 + 10;
const int INF = 1e9;
string str;
string judge(int L, int R) {//截取无标点的区域
if(!isupper(str[L]) || str[R] == ' ') return "";//首字母是大写而且尾不是空格
string tmp = "";
int pos = L;
for(int i = L; i <= R; i++) {
tmp += str[i];
if(str[i] == ' ') {//无连续空格
pos = i;
if(str[i - 1] == ' ' && i - 1 >= L) return "";
}
if(str[i] == '.' || str[i] == ',' || str[i] == '!') return "";//不包括标点
}
pos += 1;//str[pos] = ' '
int cnt = 0;//截取的最后一个单词不能有两个大写
while(1) {
if(!isalpha(str[pos])) break;
if(isupper(str[pos])) cnt++;
pos++;
}
if(cnt != 1) return "";
istringstream in(tmp);
string t;
string suoxie = "";
int size = 0;
while(in >> t) {
size++;
int cnt = 1;
if(!isupper(t[0])) return "";
suoxie += t[0];
for(int j = 1; j < t.length(); j++) {
if(isupper(t[j])) {//有其他的大写字母
cnt++;
}
}
if(cnt != 1 || t.length() == 1) {//单词有多个大写字母或者为一个字母,不满足
return "";
}
}
if(size <= 1) return "";//只有一个单词
string res = "";
res += suoxie;
res += " (";
res += tmp;
res += ")";
return res;
}
bool check(int i) {//一个单词不能有两个大写
int cnt = 0;
int pos = i;
while(1) {
if(!isalpha(str[pos])) break;
if(isupper(str[pos])) cnt++;
pos++;
}
pos = i - 1;
while (1) {
if(!isalpha(str[pos])) break;
if(isupper(str[pos])) cnt++;
pos--;
}
if(cnt >= 2) return 0;
if(islower(str[i - 1])) return 0;
return 1;
}
int main() {
while(getline(cin, str)) {
int len = str.length();
for(int i = 0; i < len; ) {
string tmp;
string res = "";
for(int j = i + 1; j < len; j++) {
tmp = judge(i, j);
if(tmp == "") {//不满足
continue;
}
else res = tmp;
}
if(res == "" || !check(i)) {//不满足,或者这个单词有两个极其以上大写字母,或者不是第一个字母大写,前面逗号句号除外
cout << str[i];
i++;
}
else {
cout << res;
int len = res.length() - 3;//减去两个括号以及第一个空格
for(int i = 0; i < res.length(); i++) {
if(isupper(res[i])) len--;
else break;
}
i += len;
}
}
cout << endl;
}
}
K题目 关于哥俩好的数字这件事
题意
数字 x,y是个「哥俩好」数字,当且仅当数字 x的数位和与数字 y 的数位和相同。
你需要找 n个不同的正整数,使得这 n个数字两两之间均为「哥俩好」数字且总和最小。
一个整数 n, 1≤n≤5000
最小的「哥俩好」数字总和。
题解
其实数据范围很小,暴力即可
but我没有过,因为我没有看到正整数,也就是1的情况下是1,不是0,啊啊啊
瞎了我的狗眼!!
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
const int MAX = 1e7 + 10;
const ll INF = 1e18;
double eps = 1e-12;
vector<int> sum[MAX];
inline void init() {
for(int i = 0; i <= MAX; i++) {
int tmp = i;
int tot = 0;
while(tmp) {
tot += tmp % 10;
tmp /= 10;
}
if(sum[tot].size() <= 5010) sum[tot].push_back(i);
}
}
int main() {
init();
int n;
scanf("%d", &n);
ll ans = INF;
if(n == 1) {
printf("1\n");
return 0;
}
for(int i = 0; i <= MAX; i++) {
if(sum[i].size() >= n) {
ll res = 0;
for(int j = 0; j < n; j++) {
res += sum[i][j];
}
if(res < ans) {
ans = res;
}
}
}
printf("%lld\n", ans);
return 0;
}