C
题目来源
解释
- 判断冠军产生的标准即判断一场都没有输的人是否唯一
- 使用STL-map,第一个值放的是sting类 即姓名 第二个值存放他们的输赢状况
- 输入a和b,如果当前姓名没有被输入过,则输入一个姓名并将输赢状况先置为1
- 使用一个map类的迭代器,注意到mp.end()指向的是最后一个元素后一个的地址
- 迭代器需要使用this指针来指向第二个值
- 记录cnt的情况,如果第二个值为1的人数严格大于1 则不能判断输赢
关于map的STL使用参考:
代码段
int main()
{
nathan;
int n;
while (cin >> n && n != 0)
{
map<string, bool> mps;
string a, b;
while (n--)
{
cin >> a >> b;
if (mps.count(a)==0) mps[a] =1;
if (mps.count(b)==0) mps[b] =1;
mps[b] =0;
}
map<string, bool>::iterator it;
int cnt = 0;
for (it = mps.begin(); it != mps.end(); it++)
if (it->second ==1) cnt++;
cout << (cnt == 1 ? "Yes" : "No") << endl;
}
}
E
题目来源
简述
- 给定一个数n
- 要求一个递增的数列,a1,a2,a3满足所有数的平方和等于n
- 首先输出一共有k个这样的数列,再输出k行数列的具体内容
解释
- 本题是典型的尺取法思想
- 首先先将右端点r推向最远方,直到满足1-r的平方和等于n
- 注意到如果一直推到r*r>n依旧没有符合的情况,则表示没有这样的数列
- 这个也作为退出while(1)循环的唯一出口
- 当sum=n时,我们将区间长度与包括左端点l和右端点r-1的数对pair同时存入ans数组中
- 然后再将左端点l向右推进
- 这时再进入第一个while循环推动右端点r直到再次满足sum=n,再次记录新的答案ans
代码段
int main()
{
ll n;
cin >> n;
ll l = 1, r = 1, sum = 0, cnt = 0;
pii ans[10000];
while (1)
{
while (sum+r*r <=n)
{
sum += r * r;
r++;
}
if (sum == n)
{
ans[cnt++] =
pii(r - l, pair<ll, ll>(l, r - 1));
}
sum -= l * l;
l++;
if (r * r > n)break;
}
cout << cnt<< endl;
for (int i = 0; i < cnt; i++)
{
cout << ans[i].first << ' ';
for (ll j = ans[i].second.first; j<= ans[i].second.second; j++)
cout << j << ' ';
cout << endl;
}
}
F
题目来源
简述
- 在数组中寻找ai和aj,给定l与r
- 要求 l<=ai+aj<=r
解释
- 这道题可以用二分法来手写处理,当然也可以使用STL
- 先将数组排序好
- 指针i遍历数组a[i]
- 对于每一个a[i]我们使用STL-upper_bound和lower_bound
- 查找仅在a[i]之前的a[j]是否有满足条件的元素
- upper_bound:指向第一个严格大于r-a[j]的元素地址
- lower_bound:指向第一个大于等于l-a[i]的元素地址
- 所以区间长度即为upper_bound-lower_bound
代码段
void solve()
{
int n, l, r;
cin >> n >> l >> r;
vector<int>a(n);
for (auto& x : a)cin >> x;
ll cnt = 0;
sort(a.begin(), a.end());
for (int i = 0; i < n; i++)
{
cnt+=
upper_bound(a.begin(), a.begin()+i, r - a[i])- lower_bound(a.begin(), a.begin()+i, l - a[i]);
}
cout << cnt << endl;
}
int main()
{
int t;
cin >> t;
while (t--)
solve();
}