A.Archmage—思维

题意:大法师蓝量上限为 n(即超过部分不计)并且起初满蓝(即 n),每秒可以花费 x 释放一次技能,每秒会自动回蓝 y 点,先用技能后结算回蓝,问 m 秒内能最多放几次技能

起初没读懂样例,实际上可能会出现中途蓝低于 x,但是可以等几秒后又可以使用技能的情况

思维:如果 y>=x,相当于这个法师不耗蓝,那么无疑每秒都可以释放技能

如果 y<x,说明每秒结束如果使用了技能会损失蓝量,可能中途会出现蓝量不足 CD 回蓝。如果硬模拟在第6测试点 TLE,仔细读题 x+y<n,说明蓝根本就不可能到达上限,m 秒内回的蓝都可以用上,所以直接整体计算释放 (n+y*(m-1))/x 次。将两个情况综合取 min 就是答案

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

//爆int
void solve(){
ll n,m,x,y;
cin>>n>>m>>x>>y;
ll tmp=(n+(m-1)*y)/x;//直接看整体
cout<<min(m,tmp)<<endl;
}

signed main()
{
ios::sync_with_stdio(false),cin.tie(0);
ll t;cin>>t;
while(t--){
solve();
}
return 0;
}

B.Bamboo Leaf Rhapsody—签到

题意:给出一系列三维坐标上的点,找出距离源点最近的点并输出距离最近的点到源点的距离(保留三位小数)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

int n;

signed main()
{
ios::sync_with_stdio(false),cin.tie(0);
while(cin>>n){
double minn=3000;
for(int i=1;i<=n;++i){
int x,y,z;
cin>>x>>y>>z;
double temp=sqrt(1.0*(pow(abs(x),2)+pow(abs(y),2)+pow(abs(z),2)));
minn=min(minn,temp);
}
cout<<fixed<<setprecision(3)<<minn<<endl;
}
return 0;
}

C. Cheat Sheet—贪心+STL容器

题意:你有一张能最多写 n 个字符的纸,m 个可能重复的单词,你需要挑选一些不重复的写到纸上,单词之间必须用空格分隔,问最多能写下几个不同的单词

思路:时间很宽松暴力就可以过,我采用了用 set 容器去重后用 vector 排序从小到大取字符写纸上

为什么不用 set 直接排序?这就涉及知识盲区了,set 容器是在插入元素的时候自动去重排序的,所以想要它按照你的要求排好序不能用 sort()(会报错,具体原因和运算符重载有关),而是应该重载其内部排序的库的运算符。与其这样不如直接再用个 sort() 支持的静态容器 vector

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <bits/stdc++.h>
using namespace std;

bool cmp(string x, string y) {
return x.size()<y.size();
}

signed main(){
ios::sync_with_stdio(false),cin.tie(0);
set<string> seta;
vector<string> vec;
int n,m;
while(cin>>n>>m){
string ch;
for(int i=1;i<=m;++i){
cin>>ch;
seta.insert(ch);
}

for(auto x:seta)vec.push_back(x);//seta排序报错?
sort(vec.begin(),vec.end(),cmp);//seta去重,改用vector

int res=0;
for(int i=0;i<vec.size();++i) {
n-=vec[i].size();
if(n>=0)res++;//成功存放一格单词+1
else break;//当前单词放入就超了,说明不能放退出
n--;//和下一格单词隔一个空格
}
cout<<res<<endl;
}
return 0;
}

L.Lottery Tickets—思维+细节

题意: 0 到 9 每个数字有 ci 个,不要求全部用完,求能组成的不含前导 0 且能被 4 整除的最大整数

思路:先不讨论结果为一位数的情况。那么不难想到其实能否整除 4 最多和后两位有关,要想数尽可能的大那么就应该保证最后来两位能整除 4 的同时用到的数尽可能的小,这样高位的数可以选择更大的数。这样先把两位数的情况按照优先级高的打表,贪心选择合适的就可以了。对于结果为个位的情况,单独看看有没有 8 4 0,有其中一个就输出(注意判断顺序)。难点在于结尾为 00 的情况,它也可以整除 4,但是不能存入打表的容器所以要特判,其次光判断是否有 2 个 0 还不行,因为前面必须有其他的数否则就出现前导 0 情况了。具体实现看代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

//一位数特殊处理,两位数及以上的只要后两位满足整除4即可,然后后两位用的每个数尽可能的小
vector<int> vec={
20,12,32,40,24,44,52,60,16,36,64,56,72,76,80,28,84,68,88,92,96
};

int a[10],b[10];

inline bool check(int x){//匹配函数
while(x){
int y=x%10;
if(b[y]==0)return 0;
else --b[y];
x/=10;
}
return 1;
}

void solve(){
memset(a,0,sizeof a);
for(int i=0;i<10;i++)
cin>>a[i];

if(a[0]>0&&a[1]+a[2]+a[3]+a[4]+a[5]+a[6]+a[7]+a[8]+a[9]==0){//只有0的情况,防止后面选择 00 出现前导0
cout<<0<<endl;
return ;
}

//以下就是存在非0的情况
int flag=0;int ret=0;//判断是不是找到了相符的尾数
for(auto x:vec){
for(int i=0;i<10;i++)//复制一份保护原有a
b[i]=a[i];

if(a[0]>=2){//特判两位数00,vector存不了
flag=2;
b[0]-=2;
break;
}

if(check(x)==1){//贪心选小较小的两位数做结尾
flag=1;ret=x;
break;
}
}

if(flag==1){
for(int i=10;i>=0;i--)//说明是某个能整除4的两位数组成的数
while(b[i]){
cout<<i;
b[i]--;
}
cout<<ret<<endl;
}
else if(flag==2){//说明是100的倍数
for(int i=10;i>=0;i--)
while(b[i]){
cout<<i;
b[i]--;
}
cout<<"00"<<endl;
}
else{//可能只有一位数也可能组成不了
if(a[8]>0)cout<<8<<endl;
else if(a[4]>0)cout<<4<<endl;
else if(a[0]>0)cout<<0<<endl;
else cout<<-1<<endl;
}
}

signed main()
{
ios::sync_with_stdio(false),cin.tie(0);
int t;cin>>t;
while(t--){
solve();
}
return 0;
}