牛客小白月赛8

A-病毒感染

题意给一颗树,然后要求这个树上到所有点权值最小的那个点。实际上这个点就是树的重心,直接去求树的重心就可以了。

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+50;
struct node {
	int v,next;
}e[maxn];
int cnt=0,front[maxn],d[maxn],f[maxn],mmin=0x3f3f3f3f;
int n,m;
inline void addedge(int u,int v) {	
	e[++cnt].v=v;
	e[cnt].next=front[u];
	front[u]=cnt;
}
void dfs(int u,int fa)
{	
	d[u]=1,f[u]=0;
	for(int i=front[u];i;i=e[i].next) {
		int v=e[i].v;
		if(v==fa) continue;
		dfs(v,u);
		d[u]+=d[v];
		f[u]=max(f[u],d[v]);
	}
	f[u]=max(f[u],n-d[u]);
	mmin=min(mmin,f[u]);
}
int main()
{
	int u,v;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;++i) {
		scanf("%d%d",&u,&v);
		addedge(u,v);
		addedge(v,u);
	}
	dfs(1,0);
	for(int i=1;i<=n;++i)
		if(f[i]==mmin) 
		printf("%d ",i);
}

B-切题之路

这个只要理解题目然后模拟即可

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll maxn=1e5+50;
struct node
{
	ll tim,le;
}p[maxn];
int main()
{	
	ll n,t,a,b,rqy=0,clccle=0;
	scanf("%lld%lld%lld%lld",&n,&t,&a,&b);
	ll rqyt=t;ll clcclet=t;
	for(ll i=1;i<=n;++i) scanf("%lld",&p[i].tim);
	for(ll i=1;i<=n;++i) scanf("%lld",&p[i].le);
	for(ll i=1;i<=n;++i)
	{
		if(p[i].le<a&&clcclet>=p[i].tim) clccle++,clcclet-=p[i].tim;
		if(p[i].le>=b&&rqyt>=p[i].tim*2) rqy++,rqyt-=2*p[i].tim;
		if(p[i].le<b&&rqyt>=p[i].tim) rqy++,rqyt-=p[i].tim;
	}
	printf("%lld %lld\n",clccle,rqy);
	return 0;
}

C-神秘钥匙

直接考虑求 k = 1 n k C n k = k = 1 n n C n 1 k 1 = n 2 n 1 \sum_{k=1}^n kC^k_n=\sum_{k=1}^n nC^{k-1}_{n-1}=n2^{n-1} 求出答案即可

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
ll fastpow(ll x , ll y)
{
	ll ans=1;
	while(y)
	{
		if(y&1) (ans*=x)%=mod;
		(x*=x)%=mod;
		y/=2;
	}
	return ans%mod;
}
int main()
{
	ll n;
	scanf("%lld",&n);
	printf("%lld",(n%mod*fastpow(2,n-1))%mod);
}

D-迷之盒子

首先我们先考虑如果没有条件约束的情形,所有得情形应当为 C n + m 1 n 1 C^{n-1}_{n+m-1} ,然后我们找出这里面所有不符合得情形的数目,我们考虑吧剩下的先划分成不合法的个数是 i = 1 m / ( k + 1 ) C n i C m + n 1 i ( k + 1 ) n 1 \sum_{i=1}^{m/{(k+1)}}C_n^iC_{m+n-1-i(k+1)}^{n-1} 答案就是两者相减即可,由于数据量比较大要用到Lucas定理来求解

#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
const ll mod=1e9+7;
ll fpow(ll x,ll y)
{
	ll ans=1;
	while(y) {
		if(y&1) (ans*=x)%=mod;
		(x*=x)%=mod;
		y/=2;
	}
	return ans%mod;
}
ll cal(ll n,ll m) {
	ll ans=1;
	for(int i=1;i<=m;++i){
		ll t1=(n-m+i)%mod;
		ll t2=i%mod;
		ans=ans*(t1*fpow(t2,mod-2)%mod)%mod;
	}
	return ans%mod;
}
ll lucas(ll n,ll m) {
	if(m==0) return 1;
	return cal(n%mod,m%mod) *lucas(n/mod,m/mod) %mod;
}
int main()
{
	ll n,m,k,ans=0; 
	scanf("%lld%lld%lld",&n,&m,&k);
	ll sum=lucas(n+m-1,n-1);
	ll upper=m/(k+1);
	for(ll i=1;i<=upper;++i)
		(ans+=lucas(n,i)*lucas(m+n-i*(k+1)-1,n-1)%mod)%=mod;
	printf("%lld\n",sum-ans);
	return 0;
}

E-诡异数字

注意到是对一个区间里面判断数字性质的问题,很容易联想到数位dp.我们一个四维参数dfs,分别保存当前的数位,前面的数位是否被限定,前驱,以及前驱重复的个数.然后就可以开始胡乱转移了

#include<bits/stdc++.h>
#define int long long
using namespace std;
typedef long long ll;
const int maxn=20;
const int mod=20020219;
int limit[maxn],len[maxn],f[maxn][11]; 
ll dfs(int pos,bool islimit,int pre,int sum)
{
	if(sum>limit[pre]) return 0;
	if(pos==0) return 1;
	if(!islimit&&f[pos][pre]!=-1) return f[pos][pre];
	int up=islimit?len[pos]:9;
	int temp=0;
	for(int i=0;i<=up;i++) 
		temp+=dfs(pos-1,islimit&&i==len[pos],i,i==pre?sum+1:1);
	return islimit?temp:f[pos][pre]=temp;
}
ll solve(ll sum)
{
	if(sum==-1) return 0;
	int cnt=0;
	while(sum){
		len[++cnt]=sum%10;
		sum/=10;
	}
	ll ans=0;
	for(int i=0;i<=len[cnt];++i)
		(ans+=dfs(cnt-1,i==len[cnt],i,1))%=mod;	
	return ans%mod;
}
signed main()
{
	int line;
	scanf("%lld",&line);
	for(int i=1;i<=line;i++)
	{
		memset(f,-1,sizeof(f));
		memset(limit,0x3f3f3f,sizeof(limit));
		ll l,r;int n;
		scanf("%lld%lld%lld",&l,&r,&n);
		for(int t=1;t<=n;++t){
			int x,len;
			scanf("%lld%lld",&x,&len);
			limit[x]=min(limit[x],len);
		}
		printf("%lld\n",(solve(r)-solve(l-1)+mod)%mod);
	}
} 

F-数列操作

裸的平衡树

#include<cstdio>
#include<algorithm>
#define FOR(i,s,t) for(register int i=s;i<=t;++i)
#define ls k<<1,l,mid
#define rs k<<1|1,mid+1,r
#define gc getchar()
using namespace std;
const int N=400011;
int n,p;
int a[N],b[N],c[N];
namespace Segment_Tree{
    int tr[N];
    inline void modify(int x,int v,int k=1,int l=1,int r=c[0]){
        tr[k]+=v;
        if(l==r)return ;
        int mid=(l+r)>>1;
        x<=mid?modify(x,v,ls):modify(x,v,rs);
    }
    inline int query_num(int x,int k=1,int l=1,int r=c[0]){
        if(l==r)return l;
        int mid=(l+r)>>1;
        return x<=tr[k<<1]?query_num(x,ls):query_num(x-tr[k<<1],rs);
    }
    inline int query_pos(int x,int type,int k=1,int l=1,int r=c[0]){
        if(l==r){
            if(type==3)return 1;
            if(type==5)return 0;
            if(type==6)return tr[k]+1;
        }
        int mid=(l+r)>>1;
        return x<=mid?query_pos(x,type,ls):(tr[k<<1]+query_pos(x,type,rs));
    }
}
using namespace Segment_Tree;
inline void disc_init(){
    sort(c+1,c+c[0]+1);
    c[0]=unique(c+1,c+c[0]+1)-c-1;
    FOR(i,1,n)
        if(a[i]!=4)b[i]=lower_bound(c+1,c+c[0]+1,b[i])-c;
}
inline int read(){
    char c;while(c=gc,c==' '||c=='\n');int data=0,f=1;
    c=='-'?f=-1:data=c-48;
    while(c=gc,c>='0'&&c<='9')data=(data<<1)+(data<<3)+c-48;
    return data*f;
}
int main(){
    n=read();
    FOR(i,1,n){
        a[i]=read();b[i]=read();
        if(a[i]!=4)c[++c[0]]=b[i];
    }
    disc_init();
    FOR(i,1,n){
        if(a[i]==1)modify(b[i],1);
        if(a[i]==2)modify(b[i],-1);
        if(a[i]==3)printf("%d\n",query_pos(b[i],3));
        if(a[i]==4)printf("%d\n",c[query_num(b[i])]);
        if(a[i]==5)printf("%d\n",c[query_num(query_pos(b[i],5))]);
        if(a[i]==6)printf("%d\n",c[query_num(query_pos(b[i],6))]);
    }
    return 0;
}

红包期望

简单的概率论问题,根据全期望公式知道前面m个人先后取值是无所谓的都是都是 0 + 2 m n 2 = m n \frac{0+\frac{2m}{n}}{2}=\frac{m}{n} ,而后面m个人的期望全部是0.

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double ld;
typedef pair<int,int> pii;
typedef vector<int> vi;
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define ini(a,x) memset(a,x,sizeof(a))
const int inf=0x3f3f3f3f;
const int mod=1e9+7;
const ld pi=acos(-1);
const ld eps=1e-9;

void read(int &x)
{
	x=0; int f=1; char ch=getchar();
	while (ch<'0'||ch>'9') { if (ch=='-')f=-1; ch=getchar(); }
	while (ch>='0'&&ch<='9') { x=x*10+ch-'0'; ch=getchar(); }
	x=x*f;
}

int main()
{
	ll m,n,T;
	scanf("%lld%lld%lld",&m,&n,&T);
	while(T--)
	{
		ll t;
		scanf("%lld",&t);
		if(t<=m) printf("%lld\n",n/m);
		else printf("0\n");
	}
	return 0;
}

H-机房网络

据说是网络流+线段树维护,目前还是知识盲区

I-路灯孤影

似乎是一个很难的dp,虽然队友一度坚持可以暴力剪枝来做qwq

J-好的序列

Rqy的毒瘤题,不知道谁会,反正我不会

猜你喜欢

转载自blog.csdn.net/qq_40859782/article/details/83385026