牛客小白月赛2 【题解完成】

359 阅读7分钟
题目难度知识点
A 数字方阵★★构造题,shuffle
B 小马过河★★计算几何,求垂足
C 真真假假签到
D 虚虚实实★★欧拉路径
E 是是非非★★Nim游戏
F 黑黑白白★★★树上博弈
G 文模拟
H 武★★bfs
I 艺★★贪心,模拟
J 美★★构造,贪心

数字方阵

image.png

image.png

#include<bits/stdc++.h>
using namespace std;
const int N=1e3+10;
int a[N][N],n;
int main(void)
{
    cin>>n;
    int cnt=1;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n-1;j++) a[i][j]=cnt++;
    for(int i=1;i<=n;i++) a[i][n]=cnt++;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            cout<<a[i][j]<<" ";
        }
        puts("");
    }
    return 0;
}
//随机生成的方法,每次随机的生成,生成后写一个check检查合理性即可。
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
const int M=1010;
int a[N],n,b[M][M];
bool check(int a[])
{
    map<int,int>mp;
    for(int i=0;i<n;i++)
        for(int j=0;j<n;j++)
                b[i][j]=a[i*n+j];
    for(int i=0;i<n;i++)
    {
        int sum=0;
        for(int j=0;j<n;j++) sum+=b[i][j];
        if(mp[sum]) return 0;
        mp[sum]++;
    }
    for(int i=0;i<n;i++)
    {
        int sum=0;
        for(int j=0;j<n;j++) sum+=b[j][i];
        if(mp[sum]) return 0;
        mp[sum]++;
    }
    int sum=0;
    for(int i=0;i<n;i++) sum+=b[i][i];
    if(mp[sum]) return 0;
    mp[sum]++;
    sum=0;
    for(int i=0,j=n-1;i<n;i++,j--) sum+=b[i][j];
    if(mp[sum]) return 0;
    return true;
}
int main(void)
{
    cin>>n;
    for(int i=0;i<n*n;i++) a[i]=i+1;
    while(1)
    {
        random_shuffle(a,a+n*n);
        if(check(a))
        {
            for(int i=0;i<n;i++)
            {
                for(int j=0;j<n;j++)
                    cout<<a[i*n+j]<<" ";
                puts("");
            }
            break;
        }
    }
    return 0;
}

小马过河

image.png

image.png

#include <iostream>
#include <cstdio>
using namespace std;

typedef double db;

void solve() {
    db x1, y1, x2, y2, x3, y3;
    cin >> x1 >> y1 >> x2 >> y2 >> x3 >> y3;
    
    db a = x2 - x3; // 方向向量的x分量
    db b = y2 - y3; // 方向向量的y分量
    
    // 计算垂足的y坐标
    db y = (b * b * y1 + a * a * y2 - a * b * (x2 - x1)) / (a * a + b * b);
    
    // 计算垂足的x坐标
    db x = (a * b * x1 + b * b * y1 - b * b * y) / (a * b);
    
    printf("%.7f %.7f\n", x, y);
}

int main() {
    int t = 1, cas = 1;
    scanf("%d", &t);
    while (t--) {
        solve();
    }
    return 0;
}

image.png

#include <iostream>
#include <cstdio>
using namespace std;

int main() {
    int T;
    cin >> T;
    while (T--) {
        double Px, Py, Ux, Uy, Vx, Vy;
        cin >> Px >> Py >> Ux >> Uy >> Vx >> Vy;
        
        double dx = Vx - Ux; // 方向向量的x分量
        double dy = Vy - Uy; // 方向向量的y分量
        
        // 计算参数t
        double t = ((Px - Ux) * dx + (Py - Uy) * dy) / (dx * dx + dy * dy);
        
        // 计算垂足坐标
        double Qx = Ux + t * dx;
        double Qy = Uy + t * dy;
        
        printf("%.10f %.10f\n", Qx, Qy);
    }
    return 0;
}

image.png 这个比较好推,上面的几种数学已经忘完了。

#include <iostream>
#include <cstdio>
using namespace std;

int main() {
    int T;
    cin >> T;
    while (T--) {
        double Px, Py, Ux, Uy, Vx, Vy;
        cin >> Px >> Py >> Ux >> Uy >> Vx >> Vy;
        
        double A=(Uy-Vy)/(Ux-Vx);
        double B=-1;
        double C=Vy-(Uy-Vy)/(Ux-Vx)*Vx;
        
        double Qx=(B*B*Px-A*(B*Py+C))/(A*A+B*B);
        double Qy=(A*A*Py-B*(A*Px+C))/(A*A+B*B);
        printf("%.10f %.10f\n", Qx, Qy);
    }
    return 0;
}

真真假假

image.png

#include<bits/stdc++.h>
using namespace std;
string s[100]={"algorithm", "bitset", "cctype", "cerrno", "clocale", "cmath", "complex", "cstdio", "cstdlib", "cstring", "ctime",
               "deque", "exception", "fstream", "functional", "limits", "list", "map", "iomanip", "ios", 
               "iosfwd", "iostream", "istream", "ostream", "queue", "set", "sstream", 
               "stack", "stdexcept", "streambuf", "string", "utility", "vector", "cwchar", "cwctype"};
int main(void)
{
    int t; cin>>t;
    while(t--)
    {
        int flag=0; string a; cin>>a;
        for(int i=0;i<35;i++) if(a==s[i]) flag=1;
        if(flag) puts("Qian");
        else puts("Kun");
    }
    return 0;
}

虚虚实实

image.png

image.png

这里是无向图,故奇的度数要么为0或者2才行,且要所有点联通才行,这样才能经过所有的点。 视频讲解

#include<bits/stdc++.h>
using namespace std;
const int N=1e3;
int p[N],d[N],s[N],t,n,m;
int find(int x)
{
    if(x!=p[x]) p[x]=find(p[x]);
    return p[x];
}
int main(void)
{
    cin>>t;
    while(t--)
    {
        cin>>n>>m;
        for(int i=1;i<=n;i++) p[i]=i,s[i]=1,d[i]=0;
        while(m--)
        {
            int a,b; cin>>a>>b;
            d[a]++,d[b]++;
            if(find(a)!=find(b))
            {
                s[find(a)]+=s[find(b)];
                p[find(b)]=find(a);
            }
        }
        int cnt=0;
        for(int i=1;i<=n;i++)
            if(d[i]&1) cnt++;
        if((cnt==0||cnt==2)&&s[find(1)]==n) puts("Zhen");
        else puts("Xun");
    }
    return 0;
}

是是非非

image.png 命题1:当场上所有豆子的异或和非零时,总存在一种方案,可以在一步以内把异或和拿到零。 命题2:当场上所有豆子的异或和为零时,无论怎么拿,异或和不可能从零变成零。 推论:当一个人开始他自己的回合时,如果场上剩下的豆子异或和为0,则这个人必败。

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
typedef long long int  LL;
LL a[N],n,m;
int main(void)
{
    cin>>n>>m;
    LL sum=0;
    for(int i=1;i<=n;i++) cin>>a[i],sum^=a[i];
    while(m--)
    {
        int l,x; cin>>l>>x;
        sum=sum^a[l]^x;
        a[l]=x;
        if(sum) puts("Kan");
        else puts("Li");
    }
    return 0;
}

黑黑白白

image.png

image.png 就是从叶子开始推,如果说某一个父亲的所有儿子有一个必败的,那该父亲就是必胜的,因为我只要让他往必败走就是我必胜了。

#include<bits/stdc++.h>
using namespace std;
const int N=1e5*2+10;
int h[N],e[N],ne[N],idx;
int st[N],parent[N],t,n,r;//parent[N],从其对应的父亲是谁。
bool ans[N];
vector<int>child[N];//存该点的所有儿子
void add(int a,int b)
{
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void bfs()
{
    memset(h,-1,sizeof h); idx=0;
    memset(st,0,sizeof st);
    memset(parent,0,sizeof parent);
    memset(ans,0,sizeof ans);
    for(int i=1;i<=n;i++) child[i].clear();
    for(int i=0;i<n-1;i++)
    {
        int a,b; cin>>a>>b;
        add(a,b),add(b,a);
    }
    parent[r]=-1;
    queue<int>q; 
    q.push(r);
    while(q.size())
    {
        int u=q.front(); q.pop();
        for(int i=h[u];i!=-1;i=ne[i])
        {
            int j=e[i];
            if(parent[j]==0)
            {
                parent[j]=u;
                child[u].push_back(j);
                q.push(j);
            }
        }
    }
    for(int i=1;i<=n;i++)
        if(child[i].size()==0) q.push(i),st[i]=1;//叶子节点
    while(q.size())
    {
        int u=q.front(); q.pop();
        int p=parent[u];
        if(p==-1) continue;
        for(int i=0;i<child[p].size();i++)//有一个儿子必败,则父亲必胜
            if(!ans[u]) ans[p]=1;
        bool flag=true;
        for(int i=0;i<child[p].size();i++)
            if(!st[child[p][i]]) flag=false;
        if(flag) q.push(p),st[p]=1;//所有儿子都已经确定好状态了,则入队。
    }
    if(ans[r]) puts("Gen");
    else puts("Dui");
}
int main(void)
{
    cin>>t;
    while(t--)
    {
        cin>>n>>r;
        bfs();
    }
    return 0;
}

image.png

#include<bits/stdc++.h>
using namespace std;
vector< pair<int,string> > ve;
int n,m;
string s;
int main(void)
{
    cin>>n>>m>>s;
    for(int i=0;i<m;i++)
    {
        string name,s1; cin>>name>>s1;
        int cnt=0;
        for(int j=0;j<n;j++) if(s1[j]==s[j]) cnt++;
        ve.push_back({n-cnt,name});
    }
    sort(ve.begin(),ve.end());
    cout<<ve[0].second<<endl;
    printf("%.2lf",(n-ve[0].first)*1.0/n*100);
    return 0;
}

image.png

#include<bits/stdc++.h>
using namespace std;
const int N=1e5*2+10;
int h[N],e[N],w[N],ne[N],idx;
int d[N],n,p,k,st[N];
void add(int a,int b,int c)
{
    e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
void dfs(int u,int s)
{
    d[u]=s,st[u]=1;
    for(int i=h[u];i!=-1;i=ne[i])
    {
        int j=e[i],ww=w[i];
        if(!st[j])
        {
            dfs(j,s+ww);
        }
    }
}
int main(void)
{
    cin>>n>>p>>k;
    memset(h,-1,sizeof h);
    for(int i=0;i<n-1;i++)
    {
        int a,b,c; cin>>a>>b>>c;
        add(a,b,c),add(b,a,c);
    }
    memset(d,-1,sizeof d);
    dfs(p,0);
    sort(d+1,d+1+n);
    cout<<d[k+1]<<endl;
    return 0;
}

image.png

可以不看,注意一下。

#include<bits/stdc++.h>
using namespace std;
typedef long long int LL;
int n,m,t;
vector< pair<LL,LL> >ve1,ve2;
int main(void)
{
    cin>>n>>m>>t;
    for(int i=0;i<n;i++)
    {
        int x,v; cin>>x>>v;
        ve1.push_back({x,v});
    }
    for(int j=0;j<m;j++)
    {
        int x,v; cin>>x>>v;
        ve2.push_back({x,v});
    }
    sort(ve1.begin(),ve1.end());
    sort(ve2.begin(),ve2.end());
    LL ans=0;
    LL p1=0,p2=0,temp1,temp2;
    for(int i=1;i<=t;i++)
    {
       if(p1<n&&ve1[p1].first<i) temp1=ve1[p1].second,p1++;
       if(p2<m&&ve2[p2].first<i) temp2=ve2[p2].second,p2++;
       ans+=max({0ll,temp1,temp2});
    }
    cout<<ans;
}

image.png

image.png

#include<bits/stdc++.h>
using namespace std;
const int N=1e5*2+10;
typedef long long int LL;
LL a[N],s[N],c[N],n;
int main(void)
{
    cin>>n;
    for(int i=1;i<=n;i++)  cin>>a[i];
    sort(a+1,a+n+1);
    int mid=n/2;
    int i=1,j=n,k=1;
    while(i<=mid&&j>=mid+1)
    {
        c[k++]=a[j--];
        c[k++]=a[i++];
    }
    while(i<=mid) c[k++]=a[i++];
    while(j>=mid+1) c[k++]=a[j--];
    s[1]=abs(c[1]-c[n]);
    for(int i=2;i<=n;i++)
    {
        s[i]+=s[i-1]+abs(c[i]-c[i-1]);
    }
    cout<<s[n]<<endl;
    return 0;
}