牛客小白月赛80 做题记录

A 矩阵快速幂签到

纯纯诈骗题,直接输出 \(n+1\) 然后取模就行。

B 又一次放学

\(n\) 个学生,第 \(i\) 个学生属于第 \(a_i\) 个班,求跑出 \(k\) 个学生之后最多有多少学生是同一个班的。

思路:开桶记录一下学生分属的班级,然后从按班级里学生人数从大到小排个序倒着接减,数量减到 \(k\) 个之后,第一个桶的数量就是答案。

#include<bits/stdc++.h>
using namespace std;
#define int long long
int read()
{
    int x;
    scanf("%lld",&x);
    return x;
}
const int N=1e5+10;
int a[N],n,m,k,cnt[N],mx;
bool cmp(int x,int y)
{
    return x>y;
}
signed main()
{
    n=read(),m=read(),k=read();
    for(int i=1;i<=n;++i) a[i]=read(),cnt[a[i]]++,mx=max(mx,a[i]);
    sort(cnt+1,cnt+1+mx,cmp);
    for(int i=mx;i>=1;i--)
    {
        while(cnt[i]>0&&k>0)
        {
            cnt[i]-=1;
            k-=1;
        }
        if(k==0) 
        {
            cout<<cnt[1]<<"\n";
            return 0;
        }
    }
    return 0;
}

C&D 又放学辣

\(n\) 学生,\(m\) 个班级。第 \(i\) 个人属于第 \(a_i\) 个班级。跑掉 \(k\) 名学生。拖堂班级没有任何学生离校。求假设恰好只有班级 \(j,j \in [1,m]\) 的老师还在拖堂,在剩下的未拖堂的班级中,留在学校的人数最多的班级的最少的可能人数是多少。

C:考虑二分答案,因为 \(n,m\) 比较小,可以暴力的枚举每个班的人数然后进行二分。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define lc k<<1
#define rc k<<1|1
#define re register
const int N=5e4+10,mod=998244353;
int read()
{
	int x;
	scanf("%d",&x);
	return x;
}
void prt(int x,int op)
{
	if(op==1) cout<<x<<" ";
	if(op==2) cout<<x<<"\n";
}
int n,m,k,mx;
int cnt[N];
bool check(int xx,int x,int cur)
{
    int dis=cnt[cur]-x,res=k-x;
    for(int i=1;i<=n;++i)
	{
        if(i==cur) continue;
        if(i==xx) continue;
        if(cnt[i]>dis)
		{
            if(res<(cnt[i]-dis)) return 0;
            res-=(cnt[i]-dis);
        }
    }
    return 1;
}
int sol(int x)
{
    if(n-cnt[x]<k) return -1;
    mx=-1;
   	for(int i=1;i<=m;++i)
	{
        if(i==x) continue;
        int l=0,r=k,mid,ans=-1;
        while(l<=r)
		{
            mid=(l+r)>>1;
            if(check(x,mid,i)) ans=mid,l=mid+1; 
			else r=mid-1;
        }
        if(ans==-1) continue;
        mx=max(mx,cnt[i]-ans);
    }
    return mx;
}
void mian()
{
	n=read(),m=read(),k=read();
    for(int i=1;i<=n;++i)
	{
        int x=read();
        cnt[x]++;
    }
    for(int i=1;i<=m;++i) printf("%d ",sol(i));
}
int main()
{
	mian();
    return 0;
}

D:因为 \(n,m\) 比较大,考虑更优的做法。预处理出人数最多的班级人数为 \(x\) 时走的人数,对于每次询问,二分人数最多的班级的人数,判断是否合法即可。

#include<bits/stdc++.h>
using namespace std;
#define int long long
int read()
{
    int x;
    scanf("%lld",&x);
    return x;
}
const int N=1e5+10;
int n,m,k,mx,l,r,ans,tmp,mid,sm,a[N],f[N],cnt[N];
signed main()
{
	n=read(),m=read(),k=read();
	for(int i=1;i<=n;++i) a[read()]+=1,sm+=1;
	for(int i=1;i<=m;++i)
    {
		mx=max(mx,a[i]),cnt[a[i]]+=1;
	}
	for(int i=mx-1;i>=0;--i)
    {
		f[i]=f[i+1]+cnt[i+1];
        cnt[i]+=cnt[i+1];
	}
	//f[x] 人数最多的班级人数为 x 时走的人数
	for(int i=1;i<=m;++i)
    {
		l=0,r=mx,ans=-1;
		if(sm-a[i]>=k)
        {
			while(l<=r)
            {
				mid=(l+r)>>1;
				if(a[i]>mid)  tmp=a[i]-mid;
                else tmp=0;
				if (f[mid]-tmp<=k)  ans=mid,r=mid-1;
				else l=mid+1;
			}
		}
		cout<<ans<<"\n";
	}
	return 0;
}

E 一种因子游戏

Alice 和 Bob 每人有 \(n\) 张牌,两个人都知道对方手里的所有牌上的数字。规则如下:
每回合,Alice 先挑自己手里牌中一张打出。然后 Bob 再从自己手里牌中挑一张打出。如果 Bob 打出的牌与 Alice 打出的牌上的数字不互质,则Alice获胜,游戏结束;否则继续进行下一回合,若双方都没有牌了,则 Bob 获胜。两人都足够聪明。现在判断最后谁能获胜。

思路:感觉像博弈论,其实又是诈骗题,因为 Bob 足够聪明,所以可以考虑将两人牌中互质的牌连边,判断是否可以构成完美匹配,若构成完美匹配,即最大匹配数为 \(n\) 则双方没牌,Bob 获胜,否则 Alice 获胜。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define lc k<<1
#define rc k<<1|1
#define re register
const int N=5e4+10,mod=998244353;
int read()
{
	int x;
	scanf("%d",&x);
	return x;
}
void prt(int x,int op)
{
	if(op==1) cout<<x<<" ";
	if(op==2) cout<<x<<"\n";
}
int mp[501][501];
int n,vis[N],match[N];
bool dfs(int u)
{
	for(int i=1;i<=n;++i)
	{
		if(mp[u][i]&&!vis[i])
		{
			vis[i]=1;
			if(!match[i]||dfs(match[i]))
			{
				match[i]=u;
				return 1;
			}
		}
		
	}
	return 0;
}
int ans;
int mat()
{
	for(int i=1;i<=n;++i)
	{
		memset(vis,0,sizeof(vis));
		if(dfs(i)) ans++;
	}
	return ans;
}
int a[N],b[N];
int main()
{
	n=read();
	for(int i=1;i<=n;++i) a[i]=read();
	for(int i=1;i<=n;++i)
	{
		b[i]=read();
		for(int j=1;j<=n;++j)
		{
			if(__gcd(a[j],b[i])==1) mp[j][i]=1;
		}
	}
	if(mat()==n) puts("Bob");
	else puts("Alice");
	return 0;
}

F 一种异或游戏

还没看,有空再写,咕咕咕~

posted @ 2023-10-31 17:15  离弦  阅读(17)  评论(0编辑  收藏  举报