【 Codeforces Round #520 (Div. 2)】A.B.C.D.E.F

本文深入探讨了五道编程竞赛题目,包括数组处理、数学优化、字符串操作、图论及树形结构的复杂问题解决策略。文章提供了详细的解题思路与代码实现,强调了巧妙的算法设计与高效的数据结构应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

由于A理解错题意导致差点全场崩盘,A想到一个巧妙地方法,但是B由于A耽误太久导致B有二十分钟不知道在写什么,写写改改,最后过了pp还是fst了,感觉CD都很简单,至少比B简单,赛后一发过了B,还是B简单(真香)O(∩_∩)O
rank 881 rating -=16


A. A Prank

题意

给你一个数组,数组大小<100
并且数组有一个性质 1&lt;=a1&lt;a2&lt;a3&lt;...&lt;an&lt;=10001&lt;=a_1&lt;a_2&lt;a_3&lt;...&lt;a_n&lt;=10001<=a1<a2<a3<...<an<=1000
在数组中可以删除连续的一段,但是要保证能按照这个性质还原数组
问删除的那段的最长长度

做法

我们发现只有连续上升超过2,才能删除,删除大小为总上升长度-2
但是首尾处理起来却不太方便
所以我们设a[0]=0;a[n+1]=1001
这样也就避免首首尾需要特判的情况。

代码

#include<iostream>
#include<stdio.h>
#include<algorithm>
using namespace std;
const int maxn = 1e5+5;
char str[maxn];
int a[maxn];
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    a[0]=0;
    a[n+1]=1001;
    int tmp=1;
    int ans=0;
    for(int i=1;i<=n+1;i++)
    {
        if(a[i]==a[i-1]+1) tmp++;
        else
        {
            ans=max(ans,tmp-2);
            tmp=1;
        }
    }
    ans=max(ans,tmp-2);
    printf("%d\n",ans);
    return 0;
}


B. Math

题意

给你一个数,每次可以进行两个操作,乘一个数或者开根
问最少多少次操作能使这个数变得最小

做法

仔细想一下就会发现,如果我们需要乘法再开根,
那么一次就能把所有需要的乘法都乘上,之后不断开根就可以
但是这里有一些细节问题,最终的最小值一定是原数的所有质因子相乘
那么我们要乘之后变成什么值才能一直开根呢
一定是每个质因子都有2k2^k2k个,而且所有质因子的k相等
于是我们先算出最小的满足情况的k是多少,然后答案就是k-1+1
因为需要k-1次开根和一次乘法
但是这里有一个坑点就是,有可能不需要乘法,什么时候不需要乘法呢
就是所有质因子的个数相同而且都是2^k个。

代码

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<set>
using namespace std;
typedef pair<int,int> pii;
const int maxn = 1e6+10;
set<int> s;
bool check(int x)
{
    int i=1;
    while(i<=x)
    {
        if(i==x) return true;
        i=i*2;
    }
    return false;
}
int main()
{
    int n;
    scanf("%d",&n);
    if(n==1)
    {
        printf("1 0\n");
        return 0;
    }
    int maxx=0;
    int ans1=1;
    for(int i=2;i<=n;i++)
    {
        if(n%i==0)
        {
            ans1=ans1*i;
            int num=0;
            while(n%i==0) n/=i,num++;
            s.insert(num);
            maxx=max(maxx,num);
        }
    }
    int tmp=1;
    int pos=0;
    for(int i=1;;i++)
    {
        if(tmp>=maxx) break;
        pos++;
        tmp=tmp*2;
    }
    int ans=pos+1;
    if(s.size()==1&&check(*s.begin()))//所有质因子个数相同而且都是2^k
    {
        ans--;
    }
    printf("%d %d\n",ans1,ans);
    return 0;
}

C. Banh-mi

题意

题意就是给你一个01串,q次询问每次询问一段区间题意就是给你一个01串,q次询问每次询问一段区间01q
每次询问询问的是:最初区间内0的权值是0,1的权值是1每次询问询问的是:最初区间内0的权值是0,1的权值是10011
每次可以移出一个字符,移除后答案加上该字符的权值每次可以移出一个字符,移除后答案加上该字符的权值
其余所有字符加上该字符的权值其余所有字符加上该字符的权值
最后询问每个区间内能获得的最大答案,每次查询是独立的最后询问每个区间内能获得的最大答案,每次查询是独立的

做法

首先我们发现,对每个区间来说,一定是一直拿1,1没有了拿0这个策略首先我们发现,对每个区间来说,一定是一直拿1,1没有了拿0这个策略110
所以问题就变为给你一个先1后0的序列来计算上面的问题所以问题就变为给你一个先1后0的序列来计算上面的问题10
而这个序列中0,1的个数我们都可以通过前缀和快速计算出来而这个序列中0,1的个数我们都可以通过前缀和快速计算出来01
我们发现对于每个1的区间,对答案的贡献是一段首项为1我们发现对于每个1的区间,对答案的贡献是一段首项为111
公比为2,长度为1的个数等比数列公比为2,长度为1的个数等比数列21
对于每个0的区间,对答案的贡献是一段首项为1那段区间对答案的贡献对于每个0的区间,对答案的贡献是一段首项为1那段区间对答案的贡献01
公比为2,长度为0的个数的等比数列公比为2,长度为0的个数的等比数列20
之后加个快速幂再加个前缀和预处理这道题就做完了“”之后加个快速幂再加个前缀和预处理这道题就做完了“”

坑点

有减法要加Mod有减法要加Mod%ModMod

代码

#include<iostream>
#include<math.h>
#include<stdio.h>
#include<algorithm>
#include<queue>
#include<map>
#include<bitset>
#include<stack>
#include<set>
#include<vector>
#include <time.h>
#include<string.h>
using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef double db;
typedef pair <int, int> pii;
typedef pair <ll, ll> pll;
typedef pair <ll, int> pli;
typedef pair <db, db> pdd;

const int maxn = 1e5+5;
const int Mod=1000000007;
const int INF = 0x3f3f3f3f;
const ll LL_INF = 0x3f3f3f3f3f3f3f3f;
const double e=exp(1);
const db PI = acos(-1);
const db ERR = 1e-10;

#define Se second
#define Fi first
#define pb push_back
#define dbg(x) cout<<#x<<" = "<< (x)<< endl
#define dbg2(x1,x2) cout<<#x1<<" = "<<x1<<" "<<#x2<<" = "<<x2<<endl
#define dbg3(x1,x2,x3) cout<<#x1<<" = "<<x1<<" "<<#x2<<" = "<<x2<<" "<<#x3<<" = "<<x3<<endl
ll pow_(ll a,ll b)
{
    ll ans=1;
    while(b)
    {
        if(b&1) ans=(ans*a)%Mod;
        b>>=1;
        a=(a*a)%Mod;
    }
    return ans;
}
ll inv(ll x)
{
    return pow_(x,Mod-2);
}
ll sum[maxn][2];
char str[maxn];
int main()
{
    //ios::sync_with_stdio(false);
    //freopen("a.txt","r",stdin);
    //freopen("b.txt","w",stdout);
    int n,q;
    scanf("%d%d",&n,&q);
    scanf("%s",str+1);
    for(int i=1;i<=n;i++)
    {
        sum[i][0]=sum[i-1][0];
        sum[i][1]=sum[i-1][1];
        if(str[i]=='0') sum[i][0]=(sum[i][0]+1)%Mod;
        else sum[i][1]=(sum[i][1]+1)%Mod;;
    }
    while(q--)
    {
        int l,r;
        scanf("%d%d",&l,&r);
        ll sum0=(sum[r][0]-sum[l-1][0]+Mod)%Mod;
        ll sum1=(sum[r][1]-sum[l-1][1]+Mod)%Mod;
        ll ans=0;
        ans=(pow_(2,sum1)-1+Mod)%Mod;
        ll st=(pow_(2,sum1)-1+Mod)%Mod;
        ll tmp=(pow_(2,sum0)-1+Mod)%Mod;
        tmp=(tmp*st)%Mod;
        ans=(ans+tmp)%Mod;
        printf("%lld\n",ans);
    }
    //cout << "time: " << (long long)clock() * 1000 / CLOCKS_PER_SEC << " ms" << endl;
    return 0;
}

 

D. Fun with Integers

题意

给你n,让你从2到n这个区间找任意两个数,
使得一个数是另一个的因子,绝对值小的可以变为绝对值大的
问你这变化过程所乘的倍数绝对值之和

做法

看样例就会发现每一对这种数对答案做四次贡献,每次的贡献是倍数

代码

#include<iostream>
#include<stdio.h>
#include<algorithm>
using namespace std;
typedef long long ll;
int main()
{
    ll n,ans=0;
    scanf("%lld",&n);
    for(ll i=2;i<=n;i++)
    {
        for(ll j=2;j*i<=n;j++)
        {
            ans+=4LL*j;
        }
    }
    printf("%lld\n",ans);
    return 0;
}


E. Company

题意

给你一颗具有n个节点的树,有q次查询,每次查询给出l,r
求(l,l+1,l+2…r-1,r)这段区间不考虑哪个节点之后能让剩余节点的lca深度尽量大

做法

这道题有好多种做法,我在做的过程中用了三种做法

首先我们要知道,不考虑一个节点能让一些点的lca发生变化的话,
这个点一定是dfs序最小的点或者dfs序最大的点。
如果能想到这个结论第一种做法就很好想


第一种做法
线段树维护区间lca,st表维护区间dfs序,这样给定一段区间之后
我们就可以通过st表找到哪两个点是dfs最小和最大的点
之后线段树上求该点左侧的区间和该点右侧的区间的lca
对dfs序最小的点求一次,对dfs序最大的点求一次,再取个max就是答案


之后的做法需要知道(猜)另一个结论
一些点的lca就是dfs序最小的点和dfs序最大的点的lca


第二种做法
这样我们用线段树维护区间dfs序,
去掉dfs序最小的点之后在剩下的两个区间查找新的dfs序最小/最大的点
求他们的lca,去掉dfs序最大的点再来一遍,取个max就是答案


第三种做法
第三种做法就是基于第二种做法的基础上,我们直接维护区间最大此大最小次小,这样就可以直接查询当前l,r之内的最大最小最小次小dfs序
删除dfs序最大的点,也就是次大dfs序的点与最小dfs序的点求lca
删除dfs序最小的点,也就是次小dfs序的点与最大dfs序的点求lca
两个取个max即可


代码

第一种做法

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
typedef long long ll;
#define dbg(x) cout<<#x<<" = "<<x<<endl
#define dbg2(x1,x2) cout<<#x1<<" = "<<x1<<" "<<#x2<<" = "<<x2<<endl
const int maxn = 1e5+10;
vector<int> G[maxn];
int deep[maxn];
int f[maxn][20];
int in[maxn],mp[maxn],time;
void dfs(int u,int fa)
{
    f[u][0]=fa;
    in[u]=++time;
    mp[time]=u;
    for(int i=1; i<=19; i++)
        f[u][i]=f[f[u][i-1]][i-1];
    for(int i=0; i<G[u].size(); i++)
    {
        int v=G[u][i];
        if(v==fa)
            continue;
        deep[v]=deep[u]+1;
        dfs(v,u);
    }
}
int lca(int x,int y)
{
    if(x==-1) return y;
    if(y==-1) return x;
    if(deep[x]<deep[y]) swap(x,y);
    for (int i=19; i>=0; i--)
    {
         if(deep[x]-(1LL<<i)>=deep[y]) x=f[x][i];
    }
    if(x==y) return x;
    for(int i=19; i>=0; i--)
        if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
    return f[x][0];
}
struct T
{
    int l,r,mid;
    int LCA;
} Tree[maxn<<2];
void push_up(int rt)
{
    Tree[rt].LCA=lca(Tree[rt<<1].LCA,Tree[rt<<1|1].LCA);
}
void build(int rt,int l,int r)
{
    Tree[rt].l=l;
    Tree[rt].r=r;
    Tree[rt].LCA=-1;
    if(l==r)
    {
        Tree[rt].LCA=l;
        return ;
    }
    int mid=Tree[rt].mid=l+r>>1;
    build(rt<<1,l,mid);
    build(rt<<1|1,mid+1,r);
    push_up(rt);
}
int query(int rt,int l,int r)
{
    if(l>r) return -1;
    if(Tree[rt].l>=l&&Tree[rt].r<=r) return Tree[rt].LCA;
    if(Tree[rt].l>r||Tree[rt].r<l) return -1;
    int ans=-1;
    if(l<=Tree[rt].mid) ans=query(rt<<1,l,r);
    if(r>Tree[rt].mid)   ans=lca(ans,query(rt<<1|1,l,r));

    return ans;
}
inline int min_(int x,int y)
{
    return x<y?x:y;
}
inline int max_(int x,int y)
{
    return x>y?x:y;
}
int f2[maxn][16],f3[maxn][16];
void build_st(int n)
{
    int p=0;
    for(int i=1; i<=n; i<<=1) p++;
    for(int i=1; i<=n; i++)
    {
        f2[i][0]=in[i];
        f3[i][0]=in[i];
    }
    for(int j=1; j<p; j++)
    {
        for(int i=1; i<=n; i++)
        {
            if(i+(1<<j-1)>n)
                f2[i][j]=f2[i][j-1];
            else
                f2[i][j]=max_(f2[i][j-1],f2[i+(1<<j-1)][j-1]);
        }
    }
    for(int j=1; j<p; j++)
    {
        for(int i=1; i<=n; i++)
        {
            if(i+(1<<j-1)>n) f3[i][j]=f3[i][j-1];
            else  f3[i][j]=min_(f3[i][j-1],f3[i+(1<<j-1)][j-1]);
        }
    }
}
int query_max(int l,int r)
{
    int p=log2(r-l+1);
    return max_(f2[l][p],f2[r-(1<<p)+1][p]);
}
int query_min(int l,int r)
{
    int p=log2(r-l+1);
    return min_(f3[l][p],f3[r-(1<<p)+1][p]);
}
int main()
{
    int n,q,x,y;
    scanf("%d%d",&n,&q);
    for(int i=2; i<=n; i++)
    {
        scanf("%d",&x);
        G[x].push_back(i);
        G[i].push_back(x);
    }
    dfs(1,0);// deep ok  lca ok dfsxu ok
    build_st(n);
    build(1,1,n);
    while(q--)
    {
        scanf("%d%d",&x,&y);
        int st=mp[query_min(x,y)];
        int en=mp[query_max(x,y)];
        int ans1=lca(query(1,x,st-1),query(1,st+1,y));
        int ans2=lca(query(1,x,en-1),query(1,en+1,y));
        if(deep[ans1]>deep[ans2]) printf("%d %d\n",st,max_(deep[ans1],deep[ans2]));
        else printf("%d %d\n",en,max_(deep[ans1],deep[ans2]));
    }
    return 0;
}

第二种做法

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
typedef long long ll;
#define dbg(x) cout<<#x<<" = "<<x<<endl
#define dbg2(x1,x2) cout<<#x1<<" = "<<x1<<" "<<#x2<<" = "<<x2<<endl
const int maxn = 1e5+10;
vector<int> G[maxn];
int deep[maxn];
int f[maxn][20];
int in[maxn],mp[maxn],time;
void dfs(int u,int fa)
{
    f[u][0]=fa;
    in[u]=++time;
    mp[time]=u;
    for(int i=1; i<=19; i++)
        f[u][i]=f[f[u][i-1]][i-1];
    for(int i=0; i<G[u].size(); i++)
    {
        int v=G[u][i];
        if(v==fa)
            continue;
        deep[v]=deep[u]+1;
        dfs(v,u);
    }
}
int lca(int x,int y)
{
    if(deep[x]<deep[y]) swap(x,y);
    for (int i=19; i>=0; i--)
    {
         if(deep[x]-(1LL<<i)>=deep[y]) x=f[x][i];
    }
    if(x==y) return x;
    for(int i=19; i>=0; i--)
        if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
    return f[x][0];
}
struct T
{
    int l,r,mid;
    int maxx,minn;
} Tree[maxn<<2];
void push_up(int rt)
{
    Tree[rt].maxx=max(Tree[rt<<1].maxx,Tree[rt<<1|1].maxx);
    Tree[rt].minn=min(Tree[rt<<1].minn,Tree[rt<<1|1].minn);
}
void build(int rt,int l,int r)
{
    Tree[rt].l=l;
    Tree[rt].r=r;
    Tree[rt].maxx=-1;
    Tree[rt].minn=1000000;
    if(l==r)
    {
        Tree[rt].maxx=in[l];
        Tree[rt].minn=in[l];
        return ;
    }
    int mid=Tree[rt].mid=l+r>>1;
    build(rt<<1,l,mid);
    build(rt<<1|1,mid+1,r);
    push_up(rt);
}
int ans_max,ans_min;
void query(int rt,int l,int r)
{
    if(l>r) return ;
    if(Tree[rt].l>r||Tree[rt].r<l) return ;
    if(Tree[rt].l>=l&&Tree[rt].r<=r)
    {
        ans_max=max(ans_max,Tree[rt].maxx);
        ans_min=min(ans_min,Tree[rt].minn);
        return;
    }
    if(l<=Tree[rt].mid) query(rt<<1,l,r);
    if(r>Tree[rt].mid)  query(rt<<1|1,l,r);
    return ;
}
int main()
{
    int n,q,x,y;
    scanf("%d%d",&n,&q);
    for(int i=2; i<=n; i++)
    {
        scanf("%d",&x);
        G[x].push_back(i);
        G[i].push_back(x);
    }
    dfs(1,0);
    build(1,1,n);
    while(q--)
    {
        scanf("%d%d",&x,&y);
        ans_max=0,ans_min=1000000;
        query(1,x,y);
        int st=mp[ans_max];
        int en=mp[ans_min];
        ans_max=0,ans_min=1000000;
        query(1,x,st-1);query(1,st+1,y);
        int ans1=deep[lca(mp[ans_max],mp[ans_min])];
        ans_max=0,ans_min=1000000;
        query(1,x,en-1);query(1,en+1,y);
        int ans2=deep[lca(mp[ans_max],mp[ans_min])];
        if(ans1>ans2) printf("%d %d\n",st,ans1);
        else printf("%d %d\n",en,ans2);
    }
    return 0;
}

第三种做法

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
typedef long long ll;
#define dbg(x) cout<<#x<<" = "<<x<<endl
#define dbg2(x1,x2) cout<<#x1<<" = "<<x1<<" "<<#x2<<" = "<<x2<<endl
const int maxn = 1e5+10;
vector<int> G[maxn];
int deep[maxn];
int f[maxn][20];
int in[maxn],mp[maxn],time;
void dfs(int u,int fa)
{
    f[u][0]=fa;
    in[u]=++time;
    mp[time]=u;
    for(int i=1; i<=19; i++)
        f[u][i]=f[f[u][i-1]][i-1];
    for(int i=0; i<G[u].size(); i++)
    {
        int v=G[u][i];
        if(v==fa)
            continue;
        deep[v]=deep[u]+1;
        dfs(v,u);
    }
}
int lca(int x,int y)
{
    if(deep[x]<deep[y]) swap(x,y);
    for (int i=19; i>=0; i--)
    {
         if(deep[x]-(1LL<<i)>=deep[y]) x=f[x][i];
    }
    if(x==y) return x;
    for(int i=19; i>=0; i--)
        if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
    return f[x][0];
}
struct T
{
    int l,r,mid;
    int maxx[2],minn[2];
} Tree[maxn<<2];
void push_up(int rt)
{
    vector<int> t;
    t.push_back(Tree[rt<<1].maxx[0]);
    t.push_back(Tree[rt<<1].maxx[1]);
    t.push_back(Tree[rt<<1|1].maxx[0]);
    t.push_back(Tree[rt<<1|1].maxx[1]);
    sort(t.begin(),t.end());
    Tree[rt].maxx[0]=t[3];
    Tree[rt].maxx[1]=t[2];

    t.clear();
    t.push_back(Tree[rt<<1].minn[0]);
    t.push_back(Tree[rt<<1].minn[1]);
    t.push_back(Tree[rt<<1|1].minn[0]);
    t.push_back(Tree[rt<<1|1].minn[1]);
    sort(t.begin(),t.end());
    Tree[rt].minn[0]=t[0];
    Tree[rt].minn[1]=t[1];
}
void build(int rt,int l,int r)
{
    Tree[rt].l=l;
    Tree[rt].r=r;
    Tree[rt].maxx[0]=-1;
    Tree[rt].maxx[1]=-1;
    Tree[rt].minn[0]=1000000;
    Tree[rt].minn[1]=1000000;
    if(l==r)
    {
        Tree[rt].maxx[0]=in[l];
        Tree[rt].minn[0]=in[l];
        return ;
    }
    int mid=Tree[rt].mid=l+r>>1;
    build(rt<<1,l,mid);
    build(rt<<1|1,mid+1,r);
    push_up(rt);
}
vector<int> maxx,minn;
bool cmp(int a,int b)
{
    return a>b;
}
void query(int rt,int l,int r)
{
    if(l>r) return ;
    if(Tree[rt].l>r||Tree[rt].r<l) return ;
    if(Tree[rt].l>=l&&Tree[rt].r<=r)
    {
        maxx.push_back(Tree[rt].maxx[0]);
        maxx.push_back(Tree[rt].maxx[1]);
        minn.push_back(Tree[rt].minn[0]);
        minn.push_back(Tree[rt].minn[1]);
        return;
    }
    if(l<=Tree[rt].mid) query(rt<<1,l,r);
    if(r>Tree[rt].mid)  query(rt<<1|1,l,r);
    return ;
}
int main()
{
    int n,q,x,y;
    scanf("%d%d",&n,&q);
    for(int i=2; i<=n; i++)
    {
        scanf("%d",&x);
        G[x].push_back(i);
        G[i].push_back(x);
    }
    dfs(1,0);
    build(1,1,n);
    while(q--)
    {
        scanf("%d%d",&x,&y);
        maxx.clear();
        minn.clear();
        query(1,x,y);
        sort(maxx.begin(),maxx.end(),cmp);
        sort(minn.begin(),minn.end());
        int ans1=deep[lca(mp[maxx[0]],mp[minn[1]])];
        int ans2=deep[lca(mp[maxx[1]],mp[minn[0]])];
        if(ans1>ans2) printf("%d %d\n",mp[minn[0]],ans1);
        else printf("%d %d\n",mp[maxx[0]],ans2);
    }
    return 0;
}

F. Upgrading Cities

题意

给你一个n个点m条边的DAG(有向无环图),问有多少个点的可到达的点数+可以被到达的点数>=n-1

做法

由于是有向无环图,我们首先考虑拓扑排序,如果A能够到达B,那么A,B肯定不会同时出现在队列中,所以如果队列中同时存在的点超过两个,这些点肯定都是不能互相到达的,也就是说对答案肯定没有贡献,之后考虑如果队列中只有一个点,那么所有没进队的点肯定都能到达,之后考虑如果队列中恰好有两个点,设两个点分别为A,B,B有一条边指向一个入度为1的点C,那么A肯定不能到达C,所以A到达不了A,B,也就是A不能对答案做贡献,如果没有这种情况,A可以到所有剩下没有进入队列的点。这是处理一个点能到哪些点的情况,对于被哪些点到达的情况,只需要反向建边再跑一边这个过程即可。两遍topo排序之后,看哪些点满足条件即可。

代码

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
const int maxn = 3e5+5;
vector<int> G[2][maxn];
int ind[2][maxn],que[maxn],n,m;
int sum[maxn];
void topsort(int pos)
{
    int qt = 0;
    for(int i = 1; i <= n; ++i)
    {
        if(ind[pos][i] == 0) que[qt++] = i;
    }
    for(int i = 0; i < qt; ++i)
    {
        int u = que[i];
        if(qt-i==1)
        {
            sum[u]+=n-qt;
        }
        else if(qt-i==2)
        {
            int u_2=que[i+1];
            int flag=0;
            for(int j=0;j<G[pos][u_2].size();++j) if(ind[pos][G[pos][u_2][j]]==1) flag=1;
            if(flag==0) sum[u]+=(n-qt);
        }
        for(int j=0;j<G[pos][u].size();++j) if(--ind[pos][G[pos][u][j]] == 0) que[qt++] = G[pos][u][j];
    }
    return ;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        G[0][u].push_back(v);
        ind[0][v]++;
        G[1][v].push_back(u);
        ind[1][u]++;
    }
    topsort(0);
    topsort(1);
    int ans=0;
    for(int i=1;i<=n;i++) if(sum[i]>=n-2) ++ans;
    printf("%d\n",ans);
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值