专栏文章

题解:CF421D Bug in Code

CF421D题解参与者 4已保存评论 5

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
5 条
当前快照
1 份
快照标识符
@miostsks
此快照首次捕获于
2025/12/03 00:34
3 个月前
此快照最后确认于
2025/12/03 00:34
3 个月前
查看原文
哇去怎么做了一晚上虽然是一边看可塑一边做的()
duel 随到的,结果嫌麻烦毙掉了正解,写出来的双指针 TLE 了 /ng
还好我和 KDL 都读错题了,最后平掉。

简要题意:
给你 nn 个无序二元组和一个参数 PP,定义一个无序二元组 (x,y)(x,y) 合法当且仅当包含 xx 的二元组集与包含 yy 的二元组集的并集大小不小于 PP
WA on #5 警示:支持数看的是鸭鸭数量而不是投票数量,一对放逐鸭同时受到一只鸭的投票,这只鸭的贡献只是 11 哦。

首先我们考虑开桶存每只鸭的吃票数量。
接着对于每个票型的情况开桶做后缀和。
这样我们确认其中一个数字时,合法二元组的数量就可以 O(1)O(1) 计算了。
具体的,我们将当前票数距离胜诉的数量放到后缀和中查找,所有不小于距离胜诉票数的票型就都可以是合法解。
小心不要越界,同时特判不能一只鸭放逐两次。
如果一只鸭就能胜诉,那么剩下 n1n-1 只鸭都可选。
但这样会算重,刚好把每一个 (x,y)(x,y) 对应的 (y,x)(y,x) 也都算进去了。我们要的是无序对,于是将答案折半即可。
诶诶好像忘了些什么,不是取并集吗,你这样不是直接将票数简单相加了?
于是对于每一个可能会因为取并集而减少票数的二元组,我们要拎出来再判断一次修改答案。
注意到只有存在一只鸭鸭把当前二元组中的两位全部举报时,才有可能因取并集而少票。
于是根据每一个鸭鸭的举报信息反过来进行判断,我们就可以做到 O(n)O(n)
我偷懒上了个 map,所以是 O(nlogn)O(n\log n) 的,也能过就是了。
做完了。

CPP
#include<bits/stdc++.h>
#define int long long
#define mk make_pair
using namespace std;
int read(){
    int sum=0,fish=1;
    char c=getchar();
    while((c<'0'||c>'9')&&c!='-')c=getchar();
    if(c=='-')fish=-1,c=getchar();
    while(c>='0'&&c<='9')sum=sum*10+(c-'0'),c=getchar();
    return sum*fish;
}
void print(int x){
    if(x<0)putchar('-'),x=-x;
    if(x<10)putchar(x+'0');
    else print(x/10),putchar(x%10+'0');
}
int a[300005],ans1,ans2;
int b[300005];
map<pair<int,int>,int>mp;
signed main(){
    int n=read(),p=read();
    for(int i=1;i<=n;i++){
        int u=read(),v=read();
        a[u]++,a[v]++;
        int U=max(u,v);
        int V=min(u,v);
        mp[mk(U,V)]++;
    }
    for(int i=1;i<=n;i++)b[a[i]]++;
    for(int i=n;i;i--)b[i]+=b[i+1];
    for(int i=1;i<=n;i++)
    if(a[i]<p)ans1+=b[p-a[i]]-(a[i]*2>=p);
    else ans1+=n-1;
    ans1>>=1;
    for(auto i:mp){
        int qwq=a[i.first.first]+a[i.first.second];
        ans2-=(qwq-i.second<p&&qwq>=p);
    }
    print(ans1+ans2);
    return 0;
}
/*
时光流转
愿你与珍爱之人
能够再次重逢
*/

评论

5 条评论,欢迎与作者交流。

正在加载评论...