基本情况
又是过了ABC。
A、B思路更多的是从数据上分析出来的,过的很顺。
C经典拿评测机来调试,甚至还RE了一次,最后终于过了。
C. Fighting Tournament
第一次改错
这题我的思路是找到规律后,优先队列加二分查找。
但是一直WA第二个点,这是我一开始的代码:
void solve()
{
int n, Q, cnt = 0; std::cin >> n >> Q;
int maxx = -1;
for (int i = 1; i <= n; i++) std::cin >> a[i], maxx = std::max(maxx, a[i]);
std::priority_queue<int,std::vector<int>,std::greater<int>> q;
q.push(a[1]);
for (int i = 2; i <= n; i++)
{
cnt++;
q.push(a[i]);
tag[q.top()].push_back(cnt);
q.pop();
if (q.top() == maxx) break;
}
while(Q--)
{
int u, k; std::cin >> u >> k;
if (k >= cnt)
{
if (a[u] == maxx) std::cout << tag[a[u]].size() + k - cnt + 1;
else std::cout << tag[a[u]].size() ;
}
else
{
auto p = std::lower_bound(tag[a[u]].begin(), tag[a[u]].end(), k);
std::cout << (p - tag[a[u]].begin()) + 1;
}
std::cout << std::endl;
}
}
可以说是漏洞满篇,第一次改错我发现了一下几个问题(可恶的是样例都没卡掉)
-
tag[a[u]].size() + k - cnt
- 这个结果是可能爆
int
的 - 前面加上
long long
强转
- 这个结果是可能爆
-
tag[q.top()].push_back(cnt);
-
这个点是我造了一组数据才发现的,(样例到底怎么过的?)。
-
经典胡言乱语,我这里开的是小优先的优先队列,明明队首是小的,而这里想要的是记录胜者的场次。
-
语句调换一下,先
pop
再剩下的top
就是最大的了。 -
q.push(a[i]); q.pop(); tag[q.top()].push_back(cnt);
-
然而提交后还是WA on test 2
第二次改错
void solve()
{
int n, Q; std::cin >> n >> Q;
long long cnt = 0;
int maxx = -1;
for (int i = 1; i <= n; i++) std::cin >> a[i], maxx = std::max(maxx, a[i]), tag[i].clear();
std::priority_queue<int,std::vector<int>,std::greater<int>> q;
q.push(a[1]);
for (int i = 2; i <= n; i++)
{
cnt++;
q.push(a[i]); q.pop();
tag[q.top()].push_back(cnt);
if (q.top() == maxx) break;
}
while(Q--)
{
int u, k; std::cin >> u >> k;
if (k >= cnt)
{
if (a[u] == maxx) std::cout << (long long) tag[a[u]].size() + k - cnt;
else std::cout << tag[a[u]].size() ;
}
else
{
auto p = std::lower_bound(tag[a[u]].begin(), tag[a[u]].end(), k);
std::cout << (long long) (p - tag[a[u]].begin()) + 1;
}
std::cout << std::endl;
}
}
还是通过造数据找到的问题。
lower_bound
我下意识的认为是找第一个小于等于 \(k\) 的位置了,(什么根据题目自适应),但实际上是找第一个大于等于 \(k\) 的位置啊!所以整个 else
都是错的,再改。
else
{
auto p = std::lower_bound(tag[a[u]].begin(), tag[a[u]].end(), k);
if (*p == k) std::cout << (long long) (p - tag[a[u]].begin()) + 1;
else
{
if (p == tag[a[u]].begin()) std::cout << 0;
else
{
p--;
std::cout << (long long) (p - tag[a[u]].begin()) + 1;
}
}
}
然后RE了。
第三次改错
这个时候思路就比较清晰了,因为RE大概率就是迭代器操作的问题,然后我就发现要是没找到怎么办
比如我要查询的数据是第 \(7\) 轮,总共比了 \(9\) 轮,所以不会被上面那个 if
处理,而是转到了 else
。
然而查询的这个人最后赢得是第 \(5\) 轮,那么此时 lower_bound
是找不到第一个大于等于 7
的数的,它会返回 tag[a[u]].end()
。
其实到目前为止也没问题,因为我下面的算法已经让 p
自减了,算出来的正确性是可以保证的。
但是,我有一个语句是 if(*p == k)
而这里当 p = tag[a[u]].end()
的时候,显然会访问一个不确定的指针指向的值,这就导致了RE
.
我是直接在这条语句上面加了特判来规避了RE,终于AC。
void solve()
{
int n, Q; std::cin >> n >> Q;
long long cnt = 0;
int maxx = -1;
for (int i = 1; i <= n; i++) std::cin >> a[i], maxx = std::max(maxx, a[i]), tag[i].clear();
std::priority_queue<int,std::vector<int>,std::greater<int>> q;
q.push(a[1]);
for (int i = 2; i <= n; i++)
{
cnt++;
q.push(a[i]); q.pop();
tag[q.top()].push_back(cnt);
if (q.top() == maxx) break;
}
while(Q--)
{
long long u, k;
std::cin >> u >> k;
if (k >= cnt)
{
if (a[u] == maxx) std::cout << (long long) tag[a[u]].size() + k - cnt;
else std::cout << tag[a[u]].size() ;
}
else
{
auto p = std::lower_bound(tag[a[u]].begin(), tag[a[u]].end(), k);
if (p == tag[a[u]].end()) std::cout << tag[a[u]].size();
else if (*p == k) std::cout << (long long) (p - tag[a[u]].begin()) + 1;
else
{
if (p == tag[a[u]].begin()) std::cout << 0;
else
{
p--;
std::cout << (long long) (p - tag[a[u]].begin()) + 1;
}
}
}
std::cout << std::endl;
}
}
标签:std,maxx,int,Codeforces,long,tag,cnt,Div,814
From: https://www.cnblogs.com/kdlyh/p/17900877.html