A
解题思路: 如总比赛次数为3,Alice获胜一局的概率为C(1,3)(即三个里面选1个) * 1/2* 1/2*1/2。因为两者获胜概率都为1/2,则后面一直都是乘n(游戏局数)个1/2,因此只需要找到前面组合数最大的位置即可。
#include<iostream>
using namespace std;
int main()
{
int n;
cin >> n;
if (n % 2 == 0)
cout << n / 2 << endl;
else
cout << n / 2 << ' ' << n - n / 2 << endl;
return 0;
}
B
解题思路: 当序列存在0或者序列全由和为0的两个数组成时(如1 2 4 0或-1 1 -2 2两种情况),答案是NO,否则答案是YES。判断即可。
#include<iostream>
#include<set>
using namespace std;
typedef long long ll;
set<ll> s;
int main()
{
int n;
ll num, ans = 0;
cin >> n;
for (int i = 0; i < n; i++)
{
cin >> num;
s.insert(num);
}
if (s.count(0) != 0)
{
cout << "NO" << endl;
return 0;
}
ans = s.size();
for (auto &i : s)
{
if (s.count(0 - i) != 0)
ans--;
}
if (ans == 0)
cout << "NO" << endl;
else
cout << "YES" << endl;
return 0;
}
C
解题思路见注释,三种方法。
1
//用vector记录前面的字符串出现的位置,输入字符串时遍历查找记录对应字符串出现位置的vector数组并加上可形成的配对数
#include<iostream>
#include<unordered_map>
#include<string>
#include<vector>
using namespace std;
typedef long long ll;
unordered_map<string, vector<int>> m;
//用vector记录str[i]出现的所有位置
string str[100005];
int main()
{
int n, k;
ll ans = 0;
cin >> n >> k;
for (int i = 0; i < n; i++)
{
cin >> str[i];
while (m[str[i]].size())//对str[i]出现的所有位置进行遍历
{
int num = m[str[i]].front();//取位置数组第一个位置进行判断
if (i - num > k + 1)//由于插入顺序,位置数组一定是由小到大排列
m[str[i]].erase(m[str[i]].begin());//因此间隔过大时前面的位置一定不满足题目要求,删除即可
else//当出现第一个和i间隔<=k的,说明后面的位置都满足
{
ans += m[str[i]].size();
break;
}
}
m[str[i]].push_back(i);
}
cout << ans << endl;
return 0;
}
2
//存储后二分查找
#include<iostream>
#include<unordered_map>
#include<vector>
#include<string>
using namespace std;
typedef long long ll;
string str;
unordered_map<string, vector<int>> m;
int main()
{
int n, k;
ll ans = 0;
cin >> n >> k;
for (int i = 0; i < n; i++)
{
cin >> str;
m[str].push_back(i);
}
for (auto i : m)
{
for (int j = 0; j < i.second.size(); j++)
{
int l = j, r = i.second.size() - 1;
while (l < r)
{
int mid = l + r >> 1;//当存在间距过大的位置时,二分找到第一个间距大于题目要求的位置,如2 4 6 7,对2遍历时,最后l=2(6的位置)
//当数组间距都满足题目要求时,二分找到最后一个满足题目要求的位置,如3 4,对3遍历时,最后l=1(4的位置)
if (i.second[mid] - i.second[j] > k + 1)
r = mid;
else
l = mid + 1;
}
if (i.second[l] - i.second[j] > k + 1)//由上对二分位置的分析,需要进行判断
l--;
ans += l - j;
}
}
cout << ans << endl;
return 0;
}
3
//感觉有点类似滚动数组
//长度为k+2的数组遍历序列
#include<iostream>
#include<unordered_map>
#include<string>
using namespace std;
typedef long long ll;
unordered_map<string, int> m;
//m记录有效区间(i-k-2,i)内str的个数
string str[100005];
int main()
{
int n, k;
ll ans = 0;
cin >> n >> k;
for (int i = 0; i < n; i++)
{
cin >> str[i];
if (i > k + 1)//当遍历完的数组长度超过k+2时,第i-k-2项前面的项和后面i项间隔一定超过题目要求,因此用--消除
m[str[i - k - 2]]--;
//如i love you you love mi mixue ice cream and tea
//当i=4(到第二个love处)便可以对m[i]--,意味第一个i不会和后面的i形成配对,有效区间内i的个数减1
ans += m[str[i]];
m[str[i]]++;
}
cout << ans << endl;
return 0;
}