A小亮的睡眠时间
思路:求一下一共花了多少时间思考,注意思考时间大于睡觉时间上限的特殊情况。
#include <iostream>
using namespace std;
int main()
{
int n;
scanf("%d", &n);
int sum = 0;
int cur;
int total = 450;
int h = 0;
int s = 0;
for(int i = 0; i < n; i++)
{
scanf("%d", &cur);
sum += cur;
}
sum = sum * 20;
total = total - sum;
if(total < 0)
{
total = 0;
}
h = total / 60;
s = total % 60;
printf("%02d:%02d\n", h, s);
}
B 小亮是个大忙人
思路:考察阅读理解+前缀和差分
-
题意写的很清楚,对于路程A到B(A<B),小亮要经过区间[A,B]中的所有站点,因此需要经过连接这些站点的路径,所以我们考虑用差分+前缀和统计每段路程的通过次数。
-
还需要明确一点,那就是从A到B和从B到A,这两种情况是等价的,都会走过相同的路径,所以在计数的时候可以同质化处理,为了维护差分的左小右大性质,在差分统计路段次数的时候还需要让min(A,B)在左,max(A,B)在右。
-
统计完路径次数以后,统计答案的时候,考虑对于通过k次的路段,是买k次不优惠的票还是买一个优惠卡然后买k次优惠的票合算即可。
-
最大优惠其实就是统计总花费的时候,在所有最合算的路段花费中选择一个最大值输出。
#include <iostream>
using namespace std;
#define int long long
const int N = 1e5 + 5;
int p[N], a[N], b[N], c[N], s[N], n, S, m, l, r, res, maxv;
signed main()
{
ios::sync_with_stdio(false), cin.tie(0);
cin >> m >> n >> S;
for (int i = 1; i <= n; i++)
cin >> p[i];
for (int i = 2; i <= m; i++)
cin >> a[i] >> b[i] >> c[i];
for (int i = 1; i < n; i++)
{
l = p[i], r = p[i + 1];
if (l > r)
swap(l, r);
s[l + 1]++, s[r + 1]--;
}
for (int i = 2; i <= m; i++)
s[i] += s[i - 1];
for (int i = 2; i <= m; i++)
res += min(s[i] * a[i], s[i] * b[i] + c[i]);
for (int i = 2; i <= m; i++)
maxv = max(maxv, min(s[i] * a[i], s[i] * b[i] + c[i]));
if (res <= S)
cout << res - maxv << endl
<< maxv << endl;
else
cout << "Infinity" << endl;
}
C小亮圆皮:
思路:看似数据结构实则贪心
-
对于长度为2的区间,一定有一个最大值一个最小值,此时我们获得有效值(max-min)。
-
对于长度更大,包含长度为2的区间的区间,由于这个区间包含刚才的区间,因此区间内的max不会减少,而区间内的min不会增加,二者差值不会变得更小。
-
因此,只需在所有区间长度为2的区间里取一个最小差值即可。
#include <iostream>
using namespace std;
const int N = 1e5 + 5;
int n, a[N], res = 0x3f3f3f3f;
int main()
{
ios::sync_with_stdio(false), cin.tie(0);
cin >> n;
for (int i = 1; i <= n; i++)
cin >> a[i];
for (int i = 1; i < n; i++)
res = min(res, abs(a[i] - a[i + 1]));
cout << res << endl;
}
D小亮想零元购:
思路:一道分类讨论的贪心
-
我们把所需凑出的价格分为需要多少k元货币rk和需要多少1元货币r1。
-
如果我们手里的k元货币ak足够,则答案为max(0,r1-a1),剩下的一元货币有多少用多少,多退少补即可。
-
如果我们手里的k元货币ak不够凑出rk个,那也先把ak个k元货币用了,得到rk=rk-ak为还需凑出的k元货币个数。
(1)接下来讨论1元货币,如果已有的1元货币多余所需1元货币,则有a1>r1,我们先把这些1元货币用了,然后剩下多少就去凑k元货币。由于k元货币的价格和1元货币都一样,都算一张货币,因此如果我们的1元货币不够凑出完整的k元货币,那还不如直接买一张k元货币,因此这种情况下的答案是max(0, rk - a1 / k)。
(2)如果手里的1元货币不足以支撑所需,那么差多少张1元买多少张一元,差多少张k元,买多少张k元,答案为 (r1 - a1) + rk。
#include <iostream>
using namespace std;
int t, m, k, r1, rk, a1, ak;
int main()
{
ios::sync_with_stdio(false), cin.tie(0);
cin >> t;
while (t--)
{
cin >> m >> k >> a1 >> ak, r1 = m % k, rk = m / k;
if (ak > rk)
cout << max(0, r1 - a1) << "\n";
else
{
rk -= ak;
if (a1 > r1)
a1 -= r1, cout << max(0, rk - a1 / k) << "\n";
else
cout << (r1 - a1) + rk << "\n";
}
}
}
E. 小亮带发明家
思路:性质题,跟我讲的硬币翻转很像。
-
首先考虑一个显然的性质,那就是翻转硬币不可能超过一次。
-
题目要求我们每次翻转都是从头开始翻任意个,那么考虑一个O(N)的策略:用flag记录当前已经确定的前k个煎饼的状态(初始为第一个煎饼的状态),然后查看第k+1个煎饼的状态,如果跟flag一致,则前k+1个煎饼的状态仍为flag;如果第k+1个煎饼的状态跟flag不同,则把前k个煎饼全翻面并更改flag,我们仍然获得了前k+1个煎饼的状态。
-
如此,可O(N)计算答案,每次更改flag对应了一次翻面,答案为flag更改的次数。注意,最后题目要求所有煎饼正面朝上,因此如果最终前n个煎饼的flag为0,还需全部翻面,次数加1。
#include <iostream>
#include <string>
using namespace std;
string s;
char flag;
int res;
int main()
{
cin >> s, flag = s[0];
for (int i = 1; i < s.size(); i++)
if (flag != s[i])
flag = s[i], res++;
if (flag != '1')
res++;
cout << res << endl;
}
F.小亮xor小亮
思路:首先你要知道异或有个性质,那就是自己异或自己得0。
-
根据题意,可以得知:b异或一遍等价于把(a异或一遍)xor(x异或n次),我们想让这个数为0。
-
我们令a数组异或的最终值为ans。
-
所以当n为偶数的时候,x总是两两相消,所以当ans本身就为0的时候,x是谁都可以(值域内任何一个数)题目要求输出最小的,那就输出0,当ans本身不为0的时候,x是谁都不行(输出-1)。
-
当n位奇数的时候,x会余下来一个,则x xor ans = 0,那么x就等于ans。
#include <bits/stdc++.h>
using namespace std;
int main()
{
ios;
int t;
cin >> t;
while (t--)
{
int n;
cin >> n;
int ans;
cin >> ans;
for (int i = 1; i <= n - 1; i++)
{
int x;
cin >> x;
ans ^= x;
}
if (n & 1)
{
cout << ans << endl;
}
else
{
if (ans == 0)
cout << 0 << endl;
else
cout << -1 << endl;
}
}
return 0;
}
G.彬彬有礼的小亮
思路:类似新生赛的那道"说的道理"。
- 从头开始扫一遍,每个位置的找一下子串是否符合目标子串,不符合就往下走看下一个位置,如果符合,就让下标直接跳过子串长度,去看后面的位置,
#include <iostream>
#include <string>
using namespace std;
int main(){
string s,t;
cin >> s >> t;
int ans = 0;
for(int i = 0;i < s.size();i ++){
if(t[0] == s[i]){
bool flag = 1;
for(int j = 0;j < t.size();j ++){
if(t[j] != s[i+j]) {
flag = 0;
break;
}
}
if(flag){
ans ++;
i += t.size()-1;
}
}
}
cout << ans << endl;
}
H. 小亮学图像处理
思路:直接预处理出来一个足够长的字母串,然后根据题意模拟即可,注意细节,多调几次就过了,看代码即可。
#include <iostream>
#include <string>
using namespace std;
int main(){
string tmp = "abcdefghijklmnopqrstuvwxyz";
string str = "";
for(int i = 1;i <= 10;i ++){
str += tmp;
}
int n;
cin >> n;
for(int i = 0;i < n/2+1 ;i ++){
for(int j = 0;j < n/2+1 ;j ++){
cout<<str[j + i];
}
for(int j = n/2-1;j >= 0;j --){
cout<<str[j + i];
}
cout<<endl;
}
for(int i = n/2-1;i >=0;i --){
for(int j = 0;j < n/2+1 ;j ++){
cout<<str[j + i];
}
for(int j = n/2-1;j >= 0;j --){
cout<<str[j + i];
}
cout<<endl;
}
}
I. 骰子大师小亮:
思路:各个骰子之间是独立的,只需模拟即可,开一个数组记录输入的序列,然后开另一个数组初始化全为7,然后开始模拟扔骰子,每次让这些数组往下减一,如果减完以后的数和输入的序列一致,那就再减一。
#include <iostream>
using namespace std;
int b[7] = {7, 7, 7, 7, 7, 7, 7}, a[7], n;
int main()
{
for (int i = 1; i <= 6; i++)
cin >> a[i];
cin >> n;
while (n--)
{
for (int i = 1; i <= 6; i++)
{
b[i]--;
if (b[i] == a[i])
b[i]--;
}
}
for (int i = 1; i <= 6; i++)
cout << b[i] << " ";
cout << endl;
}
J. 小亮被网络诈骗
思路:用map记录字母出现个数,然后看看map存了多少个字母(size)即可。
#include <bits/stdc++.h>
using namespace std;
int main()
{
map<char, int> m;
string str;
cin >> str;
int sum = 0;
for (int i = 0; i < str.size(); i++)
{
if (m[str[i]] == 0)
{
m[str[i]]++;
sum++;
}
}
if (sum % 2 == 0)
{
printf("CHAT WITH HER!\n");
}
else
{
printf("IGNORE HIM!\n");
}
return 0;
}
K. 小亮的Team:
思路:每个题是否编写解决方案是独立的,只需看三个人的数字加起来是否大于1即可。
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n;
cin >> n;
int sum = 0;
for (int i = 0; i < n; i++)
{
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
if (a + b + c >= 2)
{
sum++;
}
}
printf("%d", sum);
return 0;