其他分享
首页 > 其他分享> > Codeforces Round #678 (Div. 2) 题解 (A-E)

Codeforces Round #678 (Div. 2) 题解 (A-E)

作者:互联网

目录

A. Reorder

那个很复杂的东西就是 \(a_1+a_2+...+a_n\)

#include <bits/stdc++.h>
using namespace std;
#define repeat(i,a,b) for(int i=(a),_=(b);i<_;i++)
#define repeat_back(i,a,b) for(int i=(b)-1,_=(a);i>=_;i--)
const int N=2000010; typedef long long ll; ll read(){ll x; if(scanf("%lld",&x)==-1)exit(0); return x;}
#define int ll
void Solve(){
	int n=read(),m=read(),s=0;
	repeat(i,0,n)s+=read();
	cout<<(s==m?"YES":"NO")<<endl;
}
signed main(){
	//freopen("data.txt","r",stdin);
	int T=1; T=read();
	repeat(ca,1,T+1){
		Solve();
	}
	return 0;
}

B. Prime Square

居然能填 0。每行留两个 1,其他都填 0 即可

#include <bits/stdc++.h>
using namespace std;
#define repeat(i,a,b) for(int i=(a),_=(b);i<_;i++)
#define repeat_back(i,a,b) for(int i=(b)-1,_=(a);i>=_;i--)
const int N=2000010; typedef long long ll; ll read(){ll x; if(scanf("%lld",&x)==-1)exit(0); return x;}
#define int ll
void Solve(){
	int n=read();
	repeat(i,0,n){
		repeat(j,0,n)
			printf("%d ",(i==j || (i+1)%n==j?1:0));
		puts("");
	}
}
signed main(){
	//freopen("data.txt","r",stdin);
	int T=1; T=read();
	repeat(ca,1,T+1){
		Solve();
	}
	return 0;
}

先模拟一遍那个算法,算出 a,b(有 a 个位于 pos 前的数必须小于 x,有 b 个位于 pos 后的数必须大于 x)然后组合数计算一下(\(A_{x-1}^{a}A_{n-x}^{b}A_{n-a-b-1}^{n-a-b-1}\))

#include <bits/stdc++.h>
using namespace std;
#define repeat(i,a,b) for(int i=(a),_=(b);i<_;i++)
#define repeat_back(i,a,b) for(int i=(b)-1,_=(a);i>=_;i--)
const int N=2000010; typedef long long ll; ll read(){ll x; if(scanf("%lld",&x)==-1)exit(0); return x;}
const ll mod=1000000007;
ll mul(ll a,ll b,ll m=mod){return a*b%m;}
ll qpow(ll a,ll b,ll m=mod){
	ll ans=1;
	for(;b;a=mul(a,a,m),b>>=1)
		if(b&1)ans=mul(ans,a,m);
	return ans;
}
#define int ll
struct CC{
	static const int N=100010;
	ll fac[N],inv[N];
	CC(){
		fac[0]=1;
		repeat(i,1,N)fac[i]=fac[i-1]*i%mod;
		inv[N-1]=qpow(fac[N-1],mod-2,mod);
		repeat_back(i,1,N)inv[i-1]=inv[i]*i%mod;
	}
	ll operator()(ll a,ll b){ //a>=b
		if(a<b || b<0)return 0;
		return fac[a]*inv[a-b]%mod*inv[b]%mod;
	}
	ll A(ll a,ll b){ //a>=b
		if(a<b || b<0)return 0;
		return fac[a]*inv[a-b]%mod;
	}
}C;
int n,x,pos,a,b;
void BinarySearch(){
	int l=0,r=n; a=b=0;
	while(l<r){
		int m=(l+r)/2;
		if(m==pos)l=m+1;
		else if(m<pos)l=m+1,a++;
		else r=m,b++;
	}
}
void Solve(){
	n=read(),x=read(),pos=read();
	BinarySearch();
	cout<<C.A(x-1,a)*C.A(n-x,b)%mod*C.A(n-a-b-1,n-a-b-1)%mod<<endl;
}
signed main(){
	//freopen("data.txt","r",stdin);
	int T=1; //T=read();
	repeat(ca,1,T+1){
		Solve();
	}
	return 0;
}

D. Bandit in a City

大意:一棵树,每个节点上有一些好人,根节点有坏人。每回合每个好人会选择一个儿子节点并移动到那里,然后坏人也会这么做,不断重复知道所有人到了叶子节点。好人尽可能让被抓住的人最少,坏人尽可能让被抓住的人最多。问被抓几人

显然,问题等价于好人全部转移到叶子后叶子人数的最大值。初始在某一节点的人最终可以走到该节点子树的任意叶子,所以策略是,尽可能让这个节点的人不去最拥挤的叶子。考虑dfs,先处理这个节点的儿子的状态(总人数,叶子数,和局部答案),该节点的局部答案 = max(儿子的局部答案最大值, 总人数/叶子数(向上取整))

#include <bits/stdc++.h>
using namespace std;
#define repeat(i,a,b) for(int i=(a),_=(b);i<_;i++)
#define repeat_back(i,a,b) for(int i=(b)-1,_=(a);i>=_;i--)
const int N=200010; typedef long long ll; ll read(){ll x; if(scanf("%lld",&x)==-1)exit(0); return x;}
#define int ll
int cnt[N],sum[N],mx[N];
vector<int> a[N];
void dfs(int x){
	if(a[x].empty())cnt[x]=1;
	for(auto p:a[x]){
		dfs(p);
		sum[x]+=sum[p];
		mx[x]=max(mx[x],mx[p]);
		cnt[x]+=cnt[p];
	}
	mx[x]=max(mx[x],(sum[x]+cnt[x]-1)/cnt[x]);
}
void Solve(){
	int n=read();
	repeat(i,2,n+1){
		a[read()].push_back(i);
	}
	repeat(i,1,n+1)sum[i]=read();
	dfs(1);
	cout<<mx[1]<<endl;
}
signed main(){
	//freopen("data.txt","r",stdin);
	int T=1; //T=read();
	repeat(ca,1,T+1){
		Solve();
	}
	return 0;
}

E. Complicated Computations

大意:给一个序列,所有非空区间的mex值组成了一个集合,问这个集合的mex值

首先必须清楚一个概念,如果答案是 \(k\),那么一定没有区间的mex值等于 \(k\)。也就是说,数字 \(k\) 把整个序列划分为一些区间,如果对于这些区间,\(1..(k-1)\) 没有都出现,那么就一定没有区间的mex值等于 \(k\)

根据上述结论,思路就是让 \(k\) 从 \(1\) 开始增加,如果发现 \(k\) 满足要求,直接输出 \(k\)

那么问题就变成了,如何询问区间内 \(1..(k-1)\) 有没有都出现呢?先预处理 \(next[i]=(a[i]=a[j],j>i\) 的最小 \(j)\),然后根据 \(a[i]\) 从小到大的顺序把 \(next[i]\) 加到线段树里,线段树维护区间最大值。询问 \([x,y]\) 里是否有 \(1..(k-1)\) 这些数字,就相当于询问线段树里 \([1,x-1]\) 的最大值是否大于 \(y\)(特殊处理一下数字 \(1..(k-1)\) 第一次出现的位置,可以记为 \(next[0]\))

#include <bits/stdc++.h>
using namespace std;
#define repeat(i,a,b) for(int i=(a),_=(b);i<_;i++)
#define repeat_back(i,a,b) for(int i=(b)-1,_=(a);i>=_;i--)
const int N=200010; typedef long long ll; ll read(){ll x; if(scanf("%lld",&x)==-1)exit(0); return x;}
#define int ll
struct seg{ //zkw线段树
	#define U(a,b) max(a,b)
	const ll a0=0;
	int n; ll a[1024*1024*4*2];
	void init(int inn){
		for(n=1;n<inn;n<<=1);
		repeat(i,0,n)a[n+i]=a0;
		repeat_back(i,1,n)up(i);
	}
	void up(int x){
		a[x]=U(a[x<<1],a[(x<<1)^1]);
	}
	void update(int x,ll k){
		x+=n; a[x]=max(a[x],k);
		while(x>>=1)up(x);
	}
	ll query(int l,int r){
		ll ans=a0;
		for(l+=n-1,r+=n+1;l^r^1;l>>=1,r>>=1){
			if(~l & 1)ans=U(ans,a[l^1]);
			if(r & 1)ans=U(ans,a[r^1]);
		}
		return ans;
	}
}tr;
map<int,int> mp;
int a[N],nxt[N];
vector<int> pos[N];
void Solve(){
	int n=read(); tr.init(n+3);
	repeat(i,1,n+3)pos[i].push_back(0);
	repeat(i,1,n+1){
		a[i]=read();
		pos[a[i]].push_back(i);
	}
	repeat(i,1,n+3)mp[i]=n+1;
	repeat(i,1,n+3)pos[i].push_back(n+1);
	repeat_back(i,1,n+1){
		nxt[i]=mp[a[i]];
		mp[a[i]]=i;
	}
	if((int)pos[1].size()==n+2){cout<<1<<endl; return;} 
	repeat(i,1,n+3){
		if(i>1){
			int f=true;
			repeat(j,0,pos[i].size()-1){
				int x=pos[i][j],y=pos[i][j+1];
				if(tr.query(0,x)<y){f=false; break;}
			}
			if(f){cout<<i<<endl; return;}
		}
		repeat(j,1,pos[i].size()-1)
			tr.update(pos[i][j],nxt[pos[i][j]]);
		tr.update(0,mp[i]);
	}
}
signed main(){
	//freopen("data.txt","r",stdin);
	int T=1; //T=read();
	repeat(ca,1,T+1){
		Solve();
	}
	return 0;
}

标签:repeat,678,int,题解,ll,pos,read,Div,define
来源: https://www.cnblogs.com/axiomofchoice/p/13871847.html