牛客小白月赛24题解

题目链接

G.做题

题意:
n m n道题,总共m分钟
a i 每道题需要花a_i分钟,最多写多少题
题解:
排序,每次写时间最小的题,计算一下能写多少道就可以
l l 注意数据范围,要用ll

AC代码

#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define endl '\n'
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
//const int mod=1e9+7;
const int mod=998244353;
const double eps = 1e-10;
const double pi=acos(-1.0);
const int maxn=5e5+10;
const ll inf=0x3f3f3f3f;
const int dir[4][2]={{0,1},{1,0},{0,-1},{-1,0}};

ll a[maxn];

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    ll n,k;
    cin>>n>>k;
    for(int i=1;i<=n;i++)cin>>a[i];
    sort(a+1,a+1+n);
    ll ans=0;
    for(int i=1;i<=n;i++){
        if(k>=a[i])ans++,k-=a[i];
        if(k<=0)break;
    }
    cout<<ans;
    return 0;
}


F.斗兽棋

题意:
e l e p h a n t > t i g e r > c a t > m o u s e > e l e p h a n t elephant->tiger->cat->mouse->elephant
每种动物棋子有如上吃的关系
给两种动物,问前者是否赢或者平局
题解:
0 3 将每种动物赋上一个数0-3,然后二维数组建一个图
1 0 如果能赢或平局的关系为1,否则为0

AC代码

#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define endl '\n'
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
//const int mod=1e9+7;
const int mod=998244353;
const double eps = 1e-10;
const double pi=acos(-1.0);
const int maxn=5e5+10;
const ll inf=0x3f3f3f3f;
const int dir[4][2]={{0,1},{1,0},{0,-1},{-1,0}};

map<string,int> m;
int g[4][4]={
    1,1,1,0,
    0,1,1,1,
    1,0,1,1,
    1,1,0,1
};

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    m["elephant"]=1,m["tiger"]=2,m["cat"]=3,m["mouse"]=4;
    string s1,s2;
    cin>>s1>>s2;
    if(g[m[s1]-1][m[s2]-1])cout<<"tiangou yiwusuoyou"<<endl;
    else cout<<"tiangou txdy"<<endl;
    return 0;
}


B.组队

题意:
n n个人,每个人有各自的能力值
k 一个队伍中能力值的极差不能超过k
问最多可以多少个人一起组队
题解:
先从小到大排序,枚举每一个人作为队伍最小的
使 u p p e r _ b o u n d k a i 通过使用upper\_bound找出大于k-a_i的第一个位置
位置减一到枚举那个人的个数就是所有能在队伍里的人

AC代码

#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define endl '\n'
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
//const int mod=1e9+7;
const int mod=998244353;
const double eps = 1e-10;
const double pi=acos(-1.0);
const int maxn=5e5+10;
const ll inf=0x3f3f3f3f;
const int dir[4][2]={{0,1},{1,0},{0,-1},{-1,0}};

ll a[maxn];

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int t;
    cin>>t;
    while(t--){
        int n,k;
        cin>>n>>k;
        for(int i=1;i<=n;i++)cin>>a[i];
        sort(a+1,a+1+n);
        int ans=0;
        for(int i=1;i<=n;i++){
            int p=upper_bound(a+1,a+1+n,k+a[i])-a-1;
            ans=max(ans,p-i+1);
        }
        cout<<ans<<endl;
    }
    return 0;
}


J.建设道路

题意:
, n a i ,一共有n个城市,每个城市有一个价值a_i
现在需要再每两两城市之间建一条路
( a i a j ) 2 这条路的花费为(a_i-a_j)^2
问总共需要多少花费
题解:
n n 2 由于n的值比较大,不能进行n^2操作
a i 2 2 a i a j + a j 2 将公式展开,a_i^2-2*a_i*a_j+a_j^2
n 1 由于对每个城市来说,都要和另外n-1个城市建路
( n 1 ) a i 2 所以每个城市都要先加上一个(n-1)*a_i^2的贡献
然后只要减去两两城市之间的乘积的二倍就可以
把所有的乘积放到一块,其实就是每个城市的价值乘其他城市价值的和
+ m o d 所以减去,记得减去值的时候+mod防止出现负数

AC代码

#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define endl '\n'
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const int mod=1e9+7;
//const int mod=998244353;
const double eps = 1e-10;
const double pi=acos(-1.0);
const int maxn=1e6+10;
const ll inf=0x3f3f3f3f;
const int dir[4][2]={{0,1},{1,0},{0,-1},{-1,0}};

ll a[maxn];

int main()
{
    //ios::sync_with_stdio(false);
    //cin.tie(0);cout.tie(0);
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int n;
    scanf("%d",&n);
    ll sum=0;
    for(int i=1;i<=n;i++)scanf("%lld",&a[i]),sum+=a[i]%mod;
    ll ans=0;
    for(int i=1;i<=n;i++){
        sum=(sum-a[i]+mod)%mod;
        ans=(ans+(n-1)*a[i]%mod*a[i]%mod)%mod;
        ans=(ans-2*a[i]%mod*sum%mod+mod)%mod;
    }
    printf("%lld",ans);
    return 0;
}


I.求和

题意:
n a i 存在一棵有n个结点的树,每个点有一个价值a_i
( m ) 现在需要进行两种操作(共m次)
1. x 1.给某一个结点的价值加上x
2. 2.查询一个结点和他子树的全部价值
题解:
现在需要进行不断更新和查询
线 所以第一个想到的就是线段树或者树状数组
但是我们没办法维护每个结点的子树
d f s 就想到了用dfs序,给某个结点重新定义
l i r i 并用l_i和r_i之间的数维护的自己到所有子节点
D F S 就是利用DFS的特性,完成这个操作
然后就可以利用树状数组维护和更新前缀和
i l i r i 然后查询的点只要找到这个点i的l_i到r_i的区间大小就可以了

AC代码

#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define endl '\n'
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
//const int mod=1e9+7;
const int mod=998244353;
const double eps = 1e-10;
const double pi=acos(-1.0);
const int maxn=1e6+10;
const ll inf=0x3f3f3f3f;
const int dir[4][2]={{0,1},{1,0},{0,-1},{-1,0}};

int l[maxn],r[maxn],cnt,a[maxn];
ll c[maxn];
//树状数组
int lowbit(int x)//返还x的最低位
{
	return x&(-x);
}
ll query(int x)
{
	ll s=0;
	while(x>0)
	{
		s+=c[x];
		x-=lowbit(x);
	}
	return s;
}
void add(int x,ll v)
{
	while(x<maxn)
	{
		c[x]+=v;
		x+=lowbit(x);
	}
}
vector<int> g[maxn];
void dfs(int u,int fa){
    l[u]=++cnt;
    for(auto v:g[u]){
        if(v==fa)continue;
        dfs(v,u);
    }
    r[u]=cnt;
}

int main()
{
    //ios::sync_with_stdio(false);
    //cin.tie(0);cout.tie(0);
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int n,m,k;
    scanf("%d%d%d",&n,&m,&k);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    for(int i=1;i<n;i++){
        int u,v;
        scanf("%d%d",&u,&v);
        g[u].pb(v);
        g[v].pb(u);
    }
    dfs(k,0);
    for(int i=1;i<=n;i++)
        add(l[i],a[i]);
    while(m--){
        int op;
        scanf("%d",&op);
        if(op==1){
            int a,x;
            scanf("%d%d",&a,&x);
            add(l[a],x);
        }
        else{
            int a;
            scanf("%d",&a);
            printf("%d\n",query(r[a])-query(l[a]-1));
        }
    }

    return 0;
}

H.认认都是好朋友

题意:
1 e 9 你有1e9个手下
m a b c 你收到了m张纸条,每个纸条上有a,b,c三个数
c = 1 a b 如果c=1表示你的手下a和b是朋友
a b 否则a和b就是敌人
(朋友的朋友也是朋友)
问纸条是否会产生矛盾的地方(两个人是朋友又是敌人)
题解:
最后的提示很明显,这道题是并查集
1 e 9 但是这道题明确说了,你有1e9个手下
a b 所以说明你的a和b非常大,肯定不能开那么大的数组
a b 所以先把所有的a和b维护一下,进行一个离散操作
然后我们需要想办法判断两个人又是朋友又是敌人
我们可以用并查集先维护所有是朋友的人
然后再找所有是敌人的人,如果他们已经是朋友了,说明出现矛盾

AC代码

#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define endl '\n'
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const int mod=1e9+7;
//const int mod=998244353;
const double eps = 1e-10;
const double pi=acos(-1.0);
const int maxn=2e6+10;
const ll inf=0x3f3f3f3f;
const int dir[4][2]={{0,1},{1,0},{0,-1},{-1,0}};
inline int read(){
   int s=0,w=1;
   char ch=getchar();
   while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
   while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
   return s*w;
}
int a[maxn],b[maxn],c[maxn];
int d[maxn<<1],fa[maxn<<1];
int find(int x){
    if(fa[x]==x)return x;
    return fa[x]=find(fa[x]);
}

int main()
{
    //ios::sync_with_stdio(false);
    //cin.tie(0);cout.tie(0);
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int t;
    t=read();
    while(t--){
        int n;
        n=read();
        for(int i=1;i<=n;i++){
            a[i]=read(),b[i]=read(),c[i]=read();
            d[2*i-1]=a[i],d[2*i]=b[i];
            fa[2*i-1]=2*i-1,fa[2*i]=2*i;
        }
        sort(d+1,d+1+2*n);
        int len=unique(d+1,d+1+2*n)-d-1;
        bool f=0;
        for(int i=1;i<=n;i++){
            int x=lower_bound(d+1,d+1+len,a[i])-d;
            int y=lower_bound(d+1,d+1+len,b[i])-d;
            int p=find(x),q=find(y);
            if(c[i])
                fa[q]=p;
        }
        for(int i=1;i<=n;i++){
            int x=lower_bound(d+1,d+1+len,a[i])-d;
            int y=lower_bound(d+1,d+1+len,b[i])-d;
            int p=find(x),q=find(y);
            if(!c[i]&&p==q)f=1;
        }
        if(!f)printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}

发布了12 篇原创文章 · 获赞 10 · 访问量 3095

猜你喜欢

转载自blog.csdn.net/qq_43756519/article/details/105606873