2021年牛客暑期多校训练营3

2021年牛客暑期多校训练营3

A Guess and lies(待)

题意:

Alice有一个数y在1~n里边,让Bob去猜,每一轮,都可以询问y是否大于等于x,Alice回答是或者不是,但是Alice可以说一次谎。

现在要求对于第一轮询问的x(1~n),当Alice回答yes的时候,Bob需要最少多少轮才能确定y

题解:

注意:

代码:

B Black and white

题意:

有一个n*m的棋盘,要把所有的格子染黑,c[i] [j]表示的是染黑该位置所需要的花费,如果在一个2*2的正方形里,有三块已经被染黑了,那么剩下的那块可以被免费染黑。问将n*m的棋盘染黑所需要的最小花费是多少

题解:

假设(i,j)染成黑色时就把它当做i与j之间的一条可以联通的边,那么现在再假设(i,j), (i+1,j),(i,j+1)这三个边是联通的,那么+1就一定能到达j+1,同理可以推另外三种情况,也就是说只要求得一个最小生成树,任意的i就都能到达任意的j,也就是题中所要求得将所有的格子都给染黑

注意:

横坐标i和j虽然说有相同的数值,但是作为图来讲,是行不通的,所以j+n区别开来,遇事不决,开long long

代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+5;
#define INF 0x3f3f3f3f
typedef long long ll;
ll d[maxn];bool vis[maxn];
struct node{
    int v,dis;
    node(int _v,ll _dis):v(_v),dis(_dis){}
};
vector<node>Adj[maxn];
ll prim(int n){
    fill(d,d+maxn,INF);
    memset(vis,false,sizeof(vis));
    d[1]=0;
    ll ans=0;
    for(int i=1;i<=n;i++){
        int u=-1;int Min=INF;
        for(int j=1;j<=n;j++){//0~n-1号结点
            if(vis[j]==false&&d[j]<Min){
                Min=d[j];
                u=j;
            }
        }
        if(u==-1)return -1;//不能联通
        vis[u]=true;
        ans+=d[u];
        for(int j=0;j<Adj[u].size();j++){
            int v=Adj[u][j].v;
            if(vis[v]==false&&Adj[u][j].dis<d[v])d[v]=Adj[u][j].dis;
        }
    }
    return ans;
}
int main()
{
    int n,m;ll a,b,c,d,p;
    scanf("%d %d %lld %lld %lld %lld %lld", &n, &m, &a, &b, &c, &d, &p);
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            a=(a*a*b+a*c+d)%p;
            Adj[i].push_back({j+n,a});
            Adj[j+n].push_back({i,a});
        }
    }
    printf("%lld",prim(n+m));
    return 0;
}

C Minimum grid

题意:

给定一个n*n的网格,其中有m个网格是空的需要填充数值,现在已知了每一行的最大值bi和每一列的最大值,让你求,这个网格里面所有求和的最小值是多少

题解:

详情参考空的位置只能填上bi,ci,0所以可以理解成二分匹配问题

注意:

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e3+5;
int match[maxn];bool vis[maxn]={false};
vector<int>g[maxn];
int b[maxn],c[maxn];
int dfs(int u)//匈牙利算法
{
    for(auto to:g[u]){
        if(vis[to])continue;
        vis[to]=1;
        if(!match[to]||dfs(match[to])){//没有人和to匹配,或者它的匹配对象被别人抢走了
            match[to]=u;
            return 1;
        }
    }
    return 0;
}
int main()
{
    int n,m,k,x,y;ll ans=0;
    scanf("%d%d%d",&n,&m,&k);
    for(int i=1;i<=n;i++){//行
        cin>>b[i];ans+=b[i];
    }
    for(int i=1;i<=n;i++){//列
        cin>>c[i];ans+=c[i];
    }
    while(m--){
        scanf("%d%d",&x,&y);
        if(b[x]==c[y])g[x].emplace_back(y);//表示x和y之间存在一条边
    }
    for(int i=1;i<=n;i++){
        memset(vis,false,sizeof(vis));
        dfs(i);//将n个编号分给它们,让他们自行匹配,
    }
    for(int i=1;i<=n;i++){
        if(match[i]){
            ans-=c[i];//可以匹配成功,此时b[i] c[i]所代表的点是一样的,减少一个即可(但是-b[i]的话wa了我也不知道为啥)
        }

    }
    printf("%lld",ans);
    return 0;
}

D Count(待)

题意:

题解:

注意:

代码:

E Math

题意:

数1~n内的数字中,有多少对(x,y)满足x*x+y*y=k(xy+1) k为正整数

题解:

详情参考 首先假设(x,y)满足这个式子,固定x通过韦达定理可以求出(x,kxy)也满足条件,因为(x,y)(y,x)都可行,所以也存在(y,kyx).利用打表的方式,我们发现(x,x3)是恒成立的,代入式子求得k=x2所以可以用得到下一个式子(x3,x5x),只要按照这个公式递推下去。就能得到满足条件的(x,y)个数

注意:

虽然给出的是有四个成立的公式,但是因为限制了y>=x,所以只有两个公式

代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn=5e6+5;
typedef long long ll;
ll ans[maxn];
ll cnt=0;
void solve()
{
    ll t=1e18;
    ans[++cnt]=1;
    ll x=2,y=x*x*x,k=x*x;
    while(1)
    {
        if(y>t)break;
        ll xx=x,yy=y,m;
        while(1){
            ans[++cnt]=yy;//一直递推下去
            if(__int128(yy)*__int128(k)-__int128(xx)>t)break;
            m=xx,xx=yy;yy=k*yy-m;
        }
        x++;
        y=x*x*x;
        k=x*x;
    }
    sort(ans+1,ans+1+cnt);
}
int main()
{
    ll n,t;
    scanf("%lld",&n);
    solve();
    while(n--){
        scanf("%lld",&t);
        printf("%lld\n",upper_bound(ans+1,ans+1+cnt,t)-ans-1);
    }
    return 0;
}

F 24dian

题意:

有1-13个数,从里边随便选四个数(可重复),通过+ - * / ()最终得到24,特别的是运算的过程中需要出现分数,把所有的情况都按照字典序输出

题解:

详情参考 orz 大佬们都说暴搜就完事了,我就只能copy题解了😅

注意:

代码:

#include<bits/stdc++.h>
using namespace std;
int n,m,flag,cnt,num;
vector<double>v,ans[100009];
bool judge(double x,double y)//表示有小数
{
    if(x>(int)x+1e-9)return 1;
    if(y>(int)y+1e-9)return 1;
    if((x/y)>(int)(x/y)+1e-9)return 1;
    return 0;
}
void dfs(int x,int y,vector<double>v){
    if(x==n){//n张牌都挑完了
        if(fabs(v[0]-m)<1e-8){//此时的v[0]就是最终的运算结果和m进行比较
            ++flag;
            if(y)++cnt;
        }
        return;
    }
    int len=v.size();
    for(int i=0;i<len;i++){
        for(int j=0;j<len;j++){
            if(i==j)continue;
            vector<double>t;
            t.clear();
            for(int h=0;h<len;h++)if(h!=i&&h!=j)t.push_back(v[h]);//任选两个值进行运算,剩下的数不变全存入向量里面
            t.push_back(v[i]+v[j]);
            dfs(x+1,y,t);
            t.pop_back();
            t.push_back(v[i]-v[j]);
            dfs(x+1,y,t);
            t.pop_back();
            t.push_back(v[i]*v[j]);
            dfs(x+1,y,t);
            t.pop_back();
            t.push_back(v[i]/v[j]);
            dfs(x+1,y|judge(v[i],v[j]),t);
            t.pop_back();
        }
    }
}
bool check(vector<double>v)
{
    flag=0,cnt=0;
    dfs(1,0,v);
    if(flag==cnt&&cnt)return 1;//表示的是满足要求有小数的存在且最终答案等于m
    return 0;
}
void dfs1(int x,int pre){//随意的放置n个数到数组里面进去,再进行check看是否满足条件
    if(x==n+1){
        if(check(v))ans[num++]=v;
        return ;
    }
    for(int i=pre;i<=13;i++){//按照字典序安放
        v.push_back(i);
        dfs1(x+1,i);
        v.pop_back();
    }
}
int main()
{
    cin>>n>>m;
    dfs1(1,1);
    cout<<num<<endl;
    for(int i=0;i<num;i++){
        int t=ans[i].size();
        for(int j=0;j<t;j++)cout<<ans[i][j]<<" ";
        puts("");
    }
    return 0;
}

G Yu Ling(Ling YueZheng) and Colorful Tree(待)

题意:

题解:

注意:

代码:

H Ling Qiu, Luna and Triple Backpack(待)

题意:

题解:

注意:

代码:

I Kuriyama Mirai and Exclusive Or(待)

题意:

题解:

注意:

代码:

J Counting Triangles

题意:

给定一些边的状态(1或者0)求这些边所形成的三角形当中,相同颜色的边有多少个

题解:

对于每一个点来说都会形成一定的白边和黑边,白边数*黑边数就是对应的异色角的个数,对于一个三角形而言,只存在两种情况,异色或者同色,异色的异色角会有两个,所以只要将异色角的个数/2就是不符合条件的三角形个数,总数减去不符合条件的三角形个数就是要求得值了Cn3x

注意:

异色三角形个数是(n-1-num)*num,因为自己本身占用了一个点,剩下的点就是n-1了

代码:

#include<bits/stdc++.h>
namespace GenHelper
{
    unsigned z1,z2,z3,z4,b,u;
    unsigned get()
    {
        b=((z1<<6)^z1)>>13;
        z1=((z1&4294967294U)<<18)^b;
        b=((z2<<2)^z2)>>27;
        z2=((z2&4294967288U)<<2)^b;
        b=((z3<<13)^z3)>>21;
        z3=((z3&4294967280U)<<7)^b;
        b=((z4<<3)^z4)>>12;
        z4=((z4&4294967168U)<<13)^b;
        return (z1^z2^z3^z4);
    }
    bool read() {
        while (!u) u = get();
        bool res = u & 1;
        u >>= 1; return res;
    }
    void srand(int x)
    {
        z1=x;
        z2=(~x)^0x233333333U;
        z3=x^0x1234598766U;
        z4=(~x)+51;
        u = 0;
    }
}
using namespace GenHelper;
using namespace std;
bool edge[8005][8005];
typedef long long ll;
int main() {
    ll  n;int  seed;
    cin >> n >> seed;
    srand(seed);
    ll ans=0;
    for (ll i = 0; i < n; i++)
        for (ll j = i + 1; j < n; j++)
        {
            edge[j][i] = edge[i][j] = read();//输入的是1或者0
        }
    for(int i=0;i<n;i++){
        ll num=0;
        for(int j=0;j<n;j++){
            if(edge[i][j])num++;//对于一个点来说,它所连接的白边个数
        }
        ans+=(n-1-num)*num/2;//对于每一个点所形成的异色角
    }
    printf("%lld",n*(n-1)*(n-2)/6-ans);
    return 0;
}
posted @   Aaryn21  阅读(102)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 上周热点回顾(3.3-3.9)
· AI 智能体引爆开源社区「GitHub 热点速览」
· 写一个简单的SQL生成工具
点击右上角即可分享
微信分享提示