A. Vasya and Coins
解题思路: 整个分为两种情况
1:一个1-burle也没有,此时得不到1(2-burle不能拆开) 因此答案为1。
2:有1-burle存在,此时最多可以得到1-burle+22-burle,因此答案为1-burle+2burle+1。
对于2,当要凑奇数(1,3,5……)时,拿一个1-burle,其他用2-burle凑即可,因此1-2*2-burle的数都能凑出来,后面就用完1-burle凑出最大的数,再加1即为结果。
#include<iostream>
using namespace std;
typedef long long ll;
int main()
{
int t;
cin >> t;
while (t--)
{
ll a, b;
cin >> a >> b;
if (a == 0)
cout << 1 << endl;
else
cout << a + b * 2 + 1 << endl;
}
return 0;
}
B. Vlad and Candies
题意理解: 每次有n种类型的糖果,而Vlad每次吃要选择频率最高的那种,且连续两次吃的不能是同种类型的糖果。要判断Vlad能否按照这种方法吃完所有的糖果。
解题思路: 由题意,我们只需要判断糖果的最大频率和次大频率间差值是否<2,若是,则输出YES,反之则输出NO。
(因为当最大和次大频率满足差值<2时,他俩可以交叉减1变小到其他较小值,如减小到和第3大频率差值<2时,则这三个交叉减1又减小到更小的值,最后所有值都能在满足题目条件情况小减到0。)
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
typedef long long ll;
ll num[200005];
int main()
{
int t;
cin >> t;
while (t--)
{
int n;
cin >> n;
int flag = 0;
for (int i = 0; i < n; i++)
{
cin >> num[i];
}
sort(num, num + n);
if (n == 1 && num[0] != 1 || num[n - 1] - num[n - 2] > 1)
cout << "NO" << endl;
else
cout << "YES" << endl;
}
return 0;
}
C. Get an Even String
题意理解: 求最少删除几个字符可以使得题目所给字符串变为满意的,字符串为满意的条件有两个:
1:字符串长度为偶数。
2:对字符串中任意奇数位置的字符,要满足ai=ai+1的条件,即在它下一个位置的字符必须和它相同。
解题思路: 贪心的思想:每次取间距最短的两个相同字符。两字符中间的即为要删除的。因为这样将更多的字符留在了后面。可以避免更多字符被删除导致最后结果不是删除最少的情况。
如oaoaaaoo:当遍历到第三个字符时,两个’o’配对了,他们间距即为最小,取这两个字符留在串里,删除中间的字符’a’以达到题目满意的条件。
第一次取入后满意的字符串为:oo,接着向后遍历,每次有配对字符就取入,删除原字符串中破坏字符串满意条件的字符。如此处删去了两个’o’中间的’a’。
第二次取入后满意的字符串为:ooaa,
第三次取入后满意的字符串为:ooaaoo,因为最后两个oo配对成功被取入,最后一个’a’要被删除
#include<iostream>
#include<string>
#include<unordered_map>
using namespace std;
int main()
{
int t;
cin >> t;
while (t--)
{
string str;
unordered_map<char, int> m;
int ans = 0;
cin >> str;
for (int i = 0; i < str.size(); i++)
{
if (m[str[i]])//当m[str[i]]!=0,即原来串中已经有相同字符存在,形成配对
{
ans -= 2;//这两个字符被保留形成满意的字符串,计数减去2,最后剩下的ans就是结果
m.clear();//将m清空,即配对字符被保留,中间的字符都被删除
}
else
m[str[i]]++;//还未形成配对,将遍历到的字符存入m
ans++;//对字符串现在字符个数进行计数统计
}
cout << ans << endl;
}
}
D. Maximum Product Strikes Back
题意理解: 我们只能从数字串首尾位置进行删除操作,要求出首部删掉几个,尾部删掉几个的情况下我们能取到所有数乘积最大的数字串。
解题思路: 看了提交记录里一个大佬的写法,就是很严谨的模拟出来的,orz。然后选了几种情况的例子按照大佬的代码算了一遍,大致理解了大佬的思路。真的很服。
1: 首先是最特殊的情况,0,因为要求的是乘积最大,有0在不可能取到最大,因此0的地方是肯定要删掉的,即0将整个数字串分割成了几部分。我们要取其中乘积最大的子串。
2: 要得到乘积最大的子串,除0以外,我们还要对负数的存在情况做讨论,当负数为偶数个时,都可以取到子串里。当负数为奇数个时,我们只需要选择删掉首个负数和它前面的部分或删掉最后一个负数和它后面的部分,这时删除依据那个部分存在绝对值为2的数字数量,删除少的那部分即可。如:2 -1 2 -2 2 -1 2 2 删除前面的 2 -1可取到最大。
由于标注所用字符太多,对功能进行说明:
ans1,ans2:分别为左右两边要删掉的个数
cf12:统计第一个负数项以及它前面的项中绝对值为2的数字的个数,当它的值为-1时说明还没有出现负数
num2:当前遍历完的部分中2=绝对值为2的数字的个数
numf:当前遍历完的部分中负数的个数
fir:区间首位置
posf1:第一个负数出现的位置
ma:记录当前情况下能取到的绝对值为2的数字的个数。(乘2就是最大值)
#include<iostream>
using namespace std;
int num[200005];
int main()
{
int t;
cin >> t;
while (t--)
{
int n;
cin >> n;
for (int i = 1; i <= n; i++)
cin >> num[i];
int cf12 = -1, num2 = 0, numf = 0, fir = 0;
int ans1 = -1, ans2 = -1, posf1 = -1, ma = 0;
for (int i = 1; i <= n; i++)
{
if (num[i] == 0)//遇到0项,对区间进行更新
{
fir = i;
cf12 = -1;
num2 = 0;
numf = 0;
continue;
}
if (num[i] < 0)
numf++;
if (abs(num[i]) == 2)
num2++;
if (numf % 2 == 0)//负数个数为偶数
{
if (ma < num2)//对最大值进行更新
{
ma = num2;
ans1 = fir;
ans2 = i;
}
}
else
{
if (cf12 == -1)//cf12==-1说明第一次出现负数,记录位置
{
cf12 = num2;
posf1 = i;
}
else//出现了>=3个负数,判断是删至最前一个负数还是删至最后一个负数
{
//删除一个后整个序列中负数即为偶数个,乘积为正,就能取到最大值
//只需要对首个负数前2的个数和末尾负数后2的个数统计进行比较,删去较小一个即可(相乘只有2会使乘积变大,所以统计2的数量即可)
//因为从前往后遍历,在遍历到最后一个负数时(整个序列里负数个数为奇数的情况)ma取的是删除最后负数的当前最大值(还未对末尾负数后的2进行统计)
if (ma < num2 - cf12)//当当前绝对值为2的数的个数(包括末尾负数后的2)-首位负数前的2的个数>ma记录的2的个数时,说明最大情况应是取末尾负数的
{
ma = num2 - cf12;
ans1 = posf1;
ans2 = i;
}
}
}
}
//当ans的值仍为-1时,说明没有绝对值为2的数字(由1/0组成),乘积最大只能为1或0,直接全部删掉得到最大乘积为1(题目说明空串乘积为1)
if (ans1 == -1)//大佬的判断写法是:(ans1==-1||ans==-1||ma==0),但是我觉得这三个关联在一起,一个有变化其他的也会有,判断一个就行
cout << n << " 0\n";
else
cout << ans1 << ' ' << n - ans2 << endl;
}
return 0;
}