牛客周赛140做题报告

A 小红的区间计数

知识点:签到

思路:判断一下区间是不是包含这几个点就行了

B 小红的牛魔

知识点:模拟

思路:很经典的类括号序列问题,\(u 和 o\) 入栈的时候判断一下就行了

C 小红的矩阵计数

知识点:模拟

思路:对所有 \(L\) 进行判断就行了,判断方法有很多种,这里只给出一种

Code
点击查看代码
bool check(char c1,char c2,char c3)
{
    int o1=0,o2=0,o0=0;
    if(c1=='1')
    {
        o1++;    
    }
    if(c1=='2')
    {
        o2++;    
    }
    if(c1=='0')
    {
        o0++;    
    }
    if(c2=='1')
    {
        o1++;    
    }
    if(c2=='2')
    {
        o2++;    
    }
    if(c2=='0')
    {
        o0++;    
    }
    if(c3=='1')
    {
        o1++;    
    }
    if(c3=='2')
    {
        o2++;    
    }
    if(c3=='0')
    {
        o0++;    
    }
    if(o1==1&&o0==1&&o2==1)
    {
        return 1;
    }
    return 0;
}
char a[1004][1004];
void solve()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
             cin>>a[i][j];
        }
    }
    int ans=0;
    for(int i=2;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            char c1=a[i][j];
            char c2=a[i-1][j];
            if(j-1>=1)
            {
                if(c1!=c2&&c2!=a[i][j-1]&&c1!=a[i][j-1]&&check(c1,c2,a[i][j-1]))
                {
                    
                    ans++;
                }
                if(c1!=c2&&c2!=a[i-1][j-1]&&c1!=a[i-1][j-1]&&check(c1,c2,a[i-1][j-1]))
                {
                    ans++;
                }
            }
            if(j+1<=m)
            {
                if(c1!=c2&&c2!=a[i][j+1]&&c1!=a[i][j+1]&&check(c1,c2,a[i][j+1]))
                {
                    ans++;
                }
                if(c1!=c2&&c2!=a[i-1][j+1]&&c1!=a[i-1][j+1]&&check(c1,c2,a[i-1][j+1]))
                {
                    ans++;
                }
            }
        }
    }
    cout<<ans<<endl;
}

D E 小红的排序

知识点:DSU(并查集)

思路:遍历数组,对于每一个下标 \(i\) 来说,若不越界,都有 \(i+x\)\(i+y\) 可以直接到达,遍历完成后,一些下标会形成若干个连通块,用并查集维护,最后对于每一个 \(i\)\(a[i]\) 都应该在一个连通块里

Code
点击查看代码
void solve()
{
    cin>>n>>x>>y;
    vi p(n+1);
    for(int i=1;i<=n;i++)
    {
        cin>>p[i];    
    }
    for(int i=1;i<=n;i++)
    {
        int d=abs(i-p[i]);
        if(d%gcd(x,y)==0||d%x==0||d%y==0)
        {
            continue;
        }
        else
        {
            cout<<"No"<<endl;
            return;
        }
    }
    cout<<"Yes"<<endl;
}

注:赛时做的时候用的是裴蜀定理,想的是用 gcd(x,y)到达能到达的点

F 小红的三角形构造

知识点:trick

思路:无思路,纯典,
对于一个奇数来说,他作为一个直角边,
另外的直角边是 $\frac{n^2-1}{2} $,斜边是 $\frac{n^2+1}{2} $

对于一个偶数来说,他作为一个直角边,
另外的直角边是 \({(\frac{n}{2})}^2-1\),斜边是$ {(\frac{n}{2})}^2+1 $

Code
点击查看代码
void solve()
{
    cin>>x;
    if(x<3)
    {
        cout<<"No"<<endl;
    }
    else
    {
        cout<<"Yes"<<endl;
        if(x&1)
        {
            cout<<x<<' ';
            cout<<(x*x-1)/2<<' '<<(x*x+1)/2<<endl;
        }
        else
        {
            cout<<x<<' ';
            cout<<(x*x/4)-1<<' '<<(x*x/4)+1<<endl;
        }
    }
}

G 小红的生成树构造

知识点:DSU(并查集),最小生成树(kruskal)

思路:将边存到边集中,对于两条边分别是 \(A,B\) 或者 \(C,D\),权值为0,其他边权值为1,我们首先要排除某个点连不到与其对应的那个点的情况,将权值为0的点并到并查集里,对于每一个连通块来说,都应该有 \(A,B\) 或者 \(C,D\) 两种,如果没有两种,就不满足条件,剩下的情况全为合法情况,答案也很显然,对边集按权值进行排序,跑一遍kruskal就行了,这样最后的生成树应该是左边为 \(AB\) 树,右边为 \(CD\)
树,用一条边把他们连起来即可

Code

点击查看代码
struct node{
    int u,v,w;
};
bool cmp(node a,node b)
{
    return a.w<b.w;
}
void solve()
{
    cin>>n>>m;
    init();
    cin>>s;
    s='5'+s;
    vector<node> a;
    while(m--)
    {
        int u,v;
        cin>>u>>v;
        if(s[u]==s[v]
        ||(s[u]=='A'&&s[v]=='B')
        ||(s[u]=='B'&&s[v]=='A')
        ||(s[u]=='C'&&s[v]=='D')
        ||(s[u]=='D'&&s[v]=='C'))
        {
            a.pb({u,v,0});
        }
        else
        {
            a.pb({u,v,1});
        }
    }
    for(auto [u,v,w]:a)
    {
        if(!same(u,v)&&w==0)
        {
            join(u,v);
        }
    }
    vi via(n+1);
    vi vib(n+1);
    vi vic(n+1);
    vi vid(n+1);
    for(int i=1;i<=n;i++)
    {
        int root=find(i);
        if(s[i]=='A')via[root]=1;
        if(s[i]=='B')vib[root]=1;
        if(s[i]=='C')vic[root]=1;
        if(s[i]=='D')vid[root]=1;
    }
    for(int i=1;i<=n;i++)
    {
        int root=find(i);
        if (s[i] == 'A' || s[i] == 'B') 
        {
            if (!via[root] || !vib[root]) 
            {
                cout << "No" << endl;
                return;
            }
        } 
        else 
        {
            if (!vic[root] || !vid[root]) 
            {
                cout << "No" << endl;
                return;
            }
        }
    }
    init();
    cout<<"Yes"<<endl;
    sort(all(a),cmp);
    for(auto [u,v,w]:a)
    {
        if(!same(u,v))
        {
            join(u,v);
            cout<<u<<' '<<v<<endl;
        }
    }
}
posted @ 2026-04-19 23:52  Lambda_L  阅读(20)  评论(0)    收藏  举报