2020 China Collegiate Programming Contest Qinhuangdao Site 补题部分

已经补AEFGK

E. Exam Results

枚举+二分+动态开点权值线段树 O ( n l o g N ) O(nlogN) O(nlogN)
智商太低,想不到什么贪心只能暴力数据结构维护

对于所有学生的最高成绩只可能是 a i ( 1 ≤ i ≤ n ) a_i(1\leq i\leq n) ai(1in)或者最大 b i b_i bi,对于后面一种情况直接特殊考虑一下即可,下面主要分析最高成绩是 a i ( 1 ≤ i ≤ n ) a_i(1\leq i\leq n) ai(1in)的情况。

首先将所有学生按照 a a a从大到小排序,然后依次枚举每一个学生的 a i a_i ai作为最高成绩,假设当前这位是 a i a_i ai,那么对于 i → n i\to n in这些学生的分数肯定越大越好即所有学生的成绩应该是 a a a,统计 i → n i\to n in满足题目意思的个数只需要二分一下即可。
而对于 1 → i − 1 1\to i-1 1i1这些学生,我们知道要保证当前 a i a_i ai是最高成绩这些学生的分数一定不能是 a a a,只能是 b b b,因此每考虑一个学生后把当前学生的 b b b加入到动态开点权值线段树中,然后对于 1 → i − 1 1\to i-1 1i1这些学生只需要直接查询即可。
注意当前 a i a_i ai不能作为最高分数的情况当且仅当权值线段树中的b的最大值大于 a i a_i ai

#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#pragma GCC optimize(2)
#include<set>
#include<map>
#include<cmath>
#include<queue>
#include<random>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<unordered_map>
#include<unordered_set>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int mod=1e9+7;
const int N=200010;
struct node1
{
    int a,b;
}q[N];
bool cmp1(node1 &x,node1 &y)
{
    if(x.a==y.a) return x.b<y.b;
    return x.a>y.a;
}
bool cmp2(node1 &x,node1 &y)
{
    if(x.b==y.b) return x.a>y.a;
    return x.b>y.b;
}
int n,p;
struct node2
{
    int l,r;
    int sz;
}tree[N*40];
int root,cnt;
void insert(int &u,int l,int r,int pos)
{
    if(!u) u=++cnt;
    if(l==r) 
    {
        tree[u].sz++;
        return;
    }
    int mid=l+r>>1;
    if(pos<=mid) insert(tree[u].l,l,mid,pos);
    else insert(tree[u].r,mid+1,r,pos);
    tree[u].sz=tree[tree[u].l].sz+tree[tree[u].r].sz;
}
int query(int u,int l,int r,int L,int R)
{
    if(L>R) return 0;
    if(!u) return 0;
    if(l>=L&&r<=R) return tree[u].sz;
    int mid=l+r>>1;
    int v=0;
    if(L<=mid) v+=query(tree[u].l,l,mid,L,R);
    if(R>mid) v+=query(tree[u].r,mid+1,r,L,R);
    return v;
}
void clear(int &u,int l,int r)
{
    if(!u) return;
    if(l==r)
    {
        tree[u].sz=0;
        u=0;
        return;
    }
    int mid=l+r>>1;
    clear(tree[u].l,l,mid);
    clear(tree[u].r,mid+1,r);
    tree[u].sz=0;u=0;
}
int main()
{
    IO;
    int T=1;
    cin>>T;
    for(int ca=1;ca<=T;ca++)
    {
        cin>>n>>p;
        for(int i=1;i<=n;i++)
            cin>>q[i].a>>q[i].b;
        
        int res=0;
        sort(q+1,q+1+n,cmp1);
        for(int i=1;i<=n;i++)
        {
            int fl=(1ll*q[i].a*p+99)/100;
            if(query(root,1,1e9,q[i].a+1,1e9)>0) 
            {
                insert(root,1,1e9,q[i].b);
                continue;
            }
            int l=i,r=n;
            while(l<r)
            {
                int mid=l+r+1>>1;
                if(q[mid].a>=fl) l=mid;
                else r=mid-1;
            }
            res=max(res,r-i+1+query(root,1,1e9,fl,q[i].a));
            insert(root,1,1e9,q[i].b);
        }
        sort(q+1,q+1+n,cmp2);
        int now=1,fl=(1ll*q[1].b*p+99)/100;  //之前now=0一直wa,应该把now=1 少算了一个点
        for(int i=2;i<=n;i++)   
            if(q[i].a>=fl&&q[i].a<=q[1].b||q[i].b>=fl) now++;
        res=max(now,res);
        printf("Case #%d: %d\n",ca,res);
        clear(root,1,1e9);cnt=0;//清点
    }
    return 0;
}

F. Friendly Group

并查集维护一下连通性即可。

#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
//#pragma GCC optimize(2)
#include<set>
#include<map>
#include<cmath>
#include<queue>
#include<random>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<unordered_map>
#include<unordered_set>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int mod=1e9+7;
const int N=1000010;
int h[N],e[2*N],ne[2*N],idx;
int p[N];
int find(int x) {return x==p[x]?x:p[x]=find(p[x]);}
void add(int a,int b)
{
    e[idx]=b;
    ne[idx]=h[a];
    h[a]=idx++;
}
pii edge[N];
bool st[N];
void dfs(int u,int fa)
{
    st[u]=1;
    for(int i=h[u];i!=-1;i=ne[i])
    {
        int j=e[i];
        if(j==fa||st[j]) continue;
        dfs(j,u);
    }
}
int main()
{
    IO;
    int T=1;
    cin>>T;
    for(int ca=1;ca<=T;ca++)
    {
        
        int n,m;
        cin>>n>>m;
        for(int i=1;i<=n;i++)
        {
            p[i]=i;
            st[i]=0;
            h[i]=-1;
        }
        idx=0;
        for(int i=1;i<=m;i++) 
        {
            int a,b;
            cin>>a>>b;
            edge[i]={a,b};
            add(a,b),add(b,a);
            
        }
        for(int i=1;i<=m;i++)
        {
            int a=edge[i].first,b=edge[i].second;
            if(st[a]||st[b]) continue;
            int pa=find(a),pb=find(b);
            if(pa==pb)
                dfs(a,-1);
            else
                p[pa]=pb;
        }
        int cnt=0;
        for(int i=1;i<=n;i++) cnt-=st[i];
        for(int i=1;i<=m;i++)
        {
            int a=edge[i].first,b=edge[i].second;
            if(st[a]&&st[b]) cnt++;
        }
        printf("Case #%d: %d\n",ca,cnt);
    }
    return 0;
}

G. Good Number

按块考虑,数学题。

#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
//#pragma GCC optimize(2)
#include<set>
#include<map>
#include<cmath>
#include<queue>
#include<random>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<unordered_map>
#include<unordered_set>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int mod=1e9+7;
const int N=200010;
int n;
int main()
{
    IO;
    int T=1;
    cin>>T;
    for(int ca=1;ca<=T;ca++)
    {
        ll res=0;
        ll n,k;
        cin>>n>>k;
        if(k==1||k>=30)
        {
            printf("Case #%d: %d\n",ca,n);
            continue;
        }
        ll m=pow(n,1.0/k);
        for(int i=1;i<=m;i++)
        {
            ll l=pow(i,k);
            ll r=min(n,(long long)pow(i+1,k)-1);
            res+=r/i-(l-1)/i;
        }
        printf("Case #%d: %d\n",ca,res);
        
    }
    return 0;
}

K. Kingdom’s Power

大佬题解1大佬题解2
看了大佬的题解,我想了一个贪心:把所有叶子拿出来,然后按照深度排序,依次遍历每个叶子,当前叶子对答案的贡献:要么从前一个叶子过来的费用(lca求一下即可)要么从根节点过来的费用。然而TLE了,也不知道这样贪心对不对先记下来吧。顺便存个tarjan求lca的板子

错误orTLE代码
//TLE
#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#pragma GCC optimize(2)
#include<set>
#include<map>
#include<cmath>
#include<queue>
#include<random>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<unordered_map>
#include<unordered_set>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int mod=1e9+7;
const int N=1000010;
int h[N],e[N],ne[N],idx;
void add(int a,int b){e[idx]=b,ne[idx]=h[a],h[a]=idx++;}
int dep[N];
int res,n;
int leaf[N],cnt;
bool cmp(int x,int y){return dep[x]<dep[y];}
void dfs1(int u)
{
    
    int now=0;
    for(int i=h[u];i!=-1;i=ne[i])
    {
        int t=e[i];
        now++;
        dep[t]=dep[u]+1;
        dfs1(t);
    }
    if(!now) leaf[++cnt]=u;
}
// tarjan 求lca
vector<pii> q[N];
int anc[N],st[N],p[N];
int find(int x) {return x==p[x]?x:p[x]=find(p[x]);}
void tarjan(int u)
{
    st[u]=1;//遍历但未回溯
    for(int i=h[u];i!=-1;i=ne[i])
    {
        int j=e[i];
        if(!st[j])
        {
            tarjan(j);//遍历子树
            p[j]=u;//合并节点
        }
    }
    for(auto &t:q[u])
    {
        int y=t.first,id=t.second;
        if(st[y]==2)
            anc[id]=find(y);
    }
    st[u]=2;//结束回溯
}
int main()
{
    //IO;
    int T=1;
    scanf("%d",&T);
    for(int ca=1;ca<=T;ca++)
    {
        cin>>n;
        for(int i=1;i<=n;i++) 
        {
            h[i]=-1;
            dep[i]=0;
            p[i]=i;
            st[i]=0;
            q[i].clear();
        }
        idx=cnt=res=0;
        for(int i=2;i<=n;i++)   
        {
            int p;
            scanf("%d\n",&p);
            add(p,i);
        }
        dfs1(1);
        sort(leaf+1,leaf+1+cnt,cmp);
        for(int i=2;i<=cnt;i++)
        {
            q[leaf[i]].push_back({leaf[i-1],i});
            q[leaf[i-1]].push_back({leaf[i],i});
        }
        tarjan(1);
        int res=dep[leaf[1]];
        for(int i=2;i<=cnt;i++)
            res+=min(dep[leaf[i]],dep[leaf[i]]+dep[leaf[i-1]]-2*dep[anc[i]]);
        printf("Case #%d: %d\n",ca,res);
    }
    return 0;
}
AC代码

按照上述博客写的代码

#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
//#pragma GCC optimize(2)
#include<set>
#include<map>
#include<cmath>
#include<queue>
#include<random>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<unordered_map>
#include<unordered_set>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int mod=1e9+7;
const int N=1000010;
vector<int> e[N];
int dep[N],dist[N];
int res,n;
bool cmp(int x,int y) {return dist[x]<dist[y];};
void dfs1(int u)
{
    for(auto &t:e[u])
    {
        dep[t]=dep[u]+1;
        dfs1(t);
        dist[u]=max(dist[u],dist[t]+1);
    }
    sort(e[u].begin(),e[u].end(),cmp);
}
int dfs2(int u,int cnt)
{
    if(e[u].empty()) return res+=cnt,1;
    for(auto &t:e[u]) cnt=min(dep[u],dfs2(t,cnt+1));
    return cnt+1;
}
int main()
{
    IO;
    int T=1;
    cin>>T;
    for(int ca=1;ca<=T;ca++)
    {
        cin>>n;
        for(int i=1;i<=n;i++) 
        {
            e[i].clear();
            dep[i]=dist[i]=0;
        }
        res=0;
        for(int i=2;i<=n;i++)   
        {
            int p;
            cin>>p;
            e[p].push_back(i);
        }
        dfs1(1);
        dfs2(1,0);
        printf("Case #%d: %d\n",ca,res);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值