Educational Codeforces Round 162 (Rated for Div. 2)

不会 F 的场。

A

答案是最左的 \(1\) 和最右的 \(1\) 之间的 \(0\) 的个数。

Code
#include <bits/stdc++.h>

using namespace std;

using ll = long long;

int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);

	int t;
	cin>>t;
	while (t--){
		int n;
		cin>>n;
		int mn=-1,mx=-1,cnt=0;
		for (int i=0; i<n; i++){
			int x;
			cin>>x;
			if (x==1){
				if (mn==-1){
					mn=i;
				}
				mx=i;
				cnt++;
			}
		}
		cout<<mx-mn+1-cnt<<"\n";
	}
	return 0;
}

B

每次优先打最近的怪物。证明不难。

Code
#include <bits/stdc++.h>

using namespace std;

using ll = long long;

const int N = 3e5+5;

ll n,k;

struct node {
	ll dis,h;
	bool operator < (const node &x) const {
		return dis<x.dis;
	}
} a[N];

void solve(){
	cin>>n>>k;
	for (int i=1; i<=n; i++){
		cin>>a[i].h;
	}
	for (int i=1; i<=n; i++){
		cin>>a[i].dis;
		a[i].dis=abs(a[i].dis);
	}
	sort(a+1,a+1+n);
	ll sum=0;
	for (int i=1; i<=n; i++){
		ll mnt=(sum+a[i].h+k-1)/k;
		if (a[i].dis<mnt){
			cout<<"NO\n";
			return;
		}
		sum+=a[i].h;
	}
	cout<<"YES\n";
}

int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);

	int t;
	cin>>t;
	while (t--){
		solve();
	}
	return 0;
}

C

发现 \(1\) 只能加,不能减,至少要加 \(1\)。因此,只要 \([l,r]\) 中能减去的(即 \(\sum_{i=l}^r {a_i}-(r-l+1)\))大于等于 \(1\) 的个数就可以了。直接前缀和。

场上又写复杂了。失败。

Code
#include <bits/stdc++.h>

using namespace std;

using ll = long long;

const int N = 3e5+5;

ll bit[N];

void M(int p,ll x){
	while (p<N){
		bit[p]+=x,p+=p&-p;
	}
}

ll Q(int p){
	ll res=0;
	while (p){
		res+=bit[p],p-=p&-p;
	}
	return res;
}

int n,q;
ll c[N],sum[N];

void solve(){
	cin>>n>>q;
	for (int i=1; i<=n; i++){
		cin>>c[i];
		sum[i]=sum[i-1]+c[i]-1;
	}
	for (int i=1; i<=n; i++){
		bit[i]=0;
	}
	for (int i=1; i<=n; i++){
		if (c[i]==1){
			M(i,1);
		}
	}
	while (q--){
		int l,r;
		cin>>l>>r;
		if (l==r){
			cout<<"NO\n";
			continue;
		}
		ll cg=sum[r]-sum[l-1];
		ll nd=Q(r)-Q(l-1);
		if (cg>=nd){
			cout<<"YES\n";
		}
		else{
			cout<<"NO\n";
		}
	}
}

int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);

	int t;
	cin>>t;
	while (t--){
		solve();
	}
	return 0;
}

D

左右二分。必须:

  • 能开始吃,即不能全相同。这个可以表达为 \(\min\neq \max\)

  • 和大于这个 \(a_i\)

Code
#include <bits/stdc++.h>

using namespace std;

using ll = long long;

const int N = 3e5+5;

ll n,a[N],lg[N],mx[N][22],mn[N][22],sum[N];

void init(){
	lg[1]=0;
	for (int i=2; i<N; i++){
		lg[i]=lg[i/2]+1;
	}
}

ll qmx(ll x,ll y){
	int s=lg[y-x+1];
	return max(mx[x][s],mx[y-(1<<s)+1][s]);
}

ll qmn(ll x,ll y){
	int s=lg[y-x+1];
	return min(mn[x][s],mn[y-(1<<s)+1][s]);
}

void cal(){
	for (int i=1; i<=n; i++){
		mn[i][0]=mx[i][0]=a[i];
	}
	for (int j=1; j<=21; j++){
		for (int i=1; i+(1<<j)-1<=n; i++){
			mx[i][j]=max(mx[i][j-1],mx[i+(1<<j-1)][j-1]);
			mn[i][j]=min(mn[i][j-1],mn[i+(1<<j-1)][j-1]);
		}
	}
}

ll gts(int l,int r){
	return sum[r]-sum[l-1];
}

ll gtl(int i){
	if (a[i-1]>a[i]){
		return 1;
	}
	int l=0,r=i;
	while (l+1<r){
		int mid=l+r>>1;
		if (qmn(mid,i-1)==qmx(mid,i-1)){
			r=mid;
		}
		else{
			l=mid;
		}
	}
	int lb=0,rb=l+1;
	while (lb+1<rb){
		int mid=lb+rb>>1;
		if (gts(mid,i-1)<=a[i]){
			rb=mid;
		}
		else{
			lb=mid;
		}
	}
	if (lb==0){
		return 1e9;
	}
	return i-lb;
}

ll gtr(int i){
	if (a[i+1]>a[i]){
		return 1;
	}
	int l=i,r=n+1;
	while (l+1<r){
		int mid=l+r>>1;
		if (qmn(i+1,mid)==qmx(i+1,mid)){
			l=mid;
		}
		else{
			r=mid;
		}
	}
	int lb=r-1,rb=n+1;
	while (lb+1<rb){
		int mid=lb+rb>>1;
		if (gts(i+1,mid)<=a[i]){
			lb=mid;
		}
		else{
			rb=mid;
		}
	}
	if (rb==n+1){
		return 1e9;
	}
	return rb-i;
}

void solve(){
	cin>>n;
	for (int i=1; i<=n; i++){
		cin>>a[i];
		sum[i]=sum[i-1]+a[i];
	}
	a[n+1]=0;
	cal();
	for (int i=1; i<=n; i++){
		ll res=min(gtl(i),gtr(i));
		if (res==1e9){
			cout<<-1<<" ";
		}
		else{
			cout<<res<<" ";
		}
	}
	cout<<"\n";
}

int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);

	init();
	int t;
	cin>>t;
	while (t--){
		solve();
	}
	return 0;
}

E

建一个虚树 dp。维护 \(dp_i\) 为当前这个节点的往上还没有遇到其他同颜色节点的点的个数。就很好做了。

听说可以启发式合并,但是我不会。

Code
#include <bits/stdc++.h>

using namespace std;

using ll = long long;

using ll = long long;

const int N = 2e5+5;

int n,a[N],cnt,dfn[N],d[N],f[N][20];
vector<int> c[N],g[N];

void dfs(int u,int fa){
	dfn[u]=++cnt;
	f[u][0]=fa;
	for (int i=1; i<20; i++){
		f[u][i]=f[f[u][i-1]][i-1];
	}
	for (auto v : g[u]){
		if (v^fa){
			d[v]=d[u]+1,dfs(v,u);
		}
	}
}

bool cmp(int x,int y){
	return dfn[x]<dfn[y];
}

int lca(int u,int v){
	if (d[u]>d[v]){
		swap(u,v);
	}
	int dif=d[v]-d[u];
	for (int i=0; i<20; i++){
		if (dif>>i&1){
			v=f[v][i];
		}
	}
	if (u==v){
		return u;
	}
	for (int i=19; i>=0; i--){
		if (f[u][i]!=f[v][i]){
			u=f[u][i],v=f[v][i];
		}
	}
	return f[u][0];
}

int st[N],top,is[N];

void bd(int i){
	g[1].clear();
	top=1;
	st[top]=1;
	for (auto u : c[i]){
		is[u]=1;
		if (u!=1){
			int lc=lca(u,st[top]);
			if (lc!=st[top]){
				while (dfn[st[top-1]]>dfn[lc]){
					g[st[top-1]].push_back(st[top]);
					top--;
				}
				if (dfn[lc]>dfn[st[top-1]]){
					g[lc].clear();
					g[lc].push_back(st[top]);
					st[top]=lc;
				}
				else{
					g[lc].push_back(st[top--]);
				}
			}
			g[u].clear();
			st[++top]=u;
		}
	}
	for (int j=1; j<top; j++){
		g[st[j]].push_back(st[j+1]);
	}
}

ll ans,dp[N];

void dfs2(int u){
	if (g[u].size()==0){
		dp[u]=is[u]?1:0;
		return;
	}
	ll sum=0;
	for (auto v : g[u]){
		dfs2(v);
		sum+=dp[v];
	}
	if (is[u]){
		ans+=sum;
		dp[u]=1;
	}
	else{
		ll ad=0;
		for (auto v : g[u]){
			ad+=1ll*dp[v]*(sum-dp[v]);
		}
		ad=ad/2;
		ans+=ad;
		dp[u]=sum;
	}
}

void solve(){
	cin>>n;
	cnt=0;
	for (int i=1; i<=n; i++){
		g[i].clear();
		c[i].clear();
	}
	for (int i=1; i<=n; i++){
		int x;
		cin>>x;
		c[x].push_back(i);
	}
	for (int i=1; i<n; i++){
		int u,v;
		cin>>u>>v;
		g[u].push_back(v);
		g[v].push_back(u);
	}
	dfs(1,0);
	ans=0;
	for (int i=1; i<=n; i++){
		sort(c[i].begin(),c[i].end(),cmp);
		bd(i);
		dfs2(1);
		for (auto u : c[i]){
			is[u]=0;
		}
	}
	cout<<ans<<"\n";
}

int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);

	int t;
	cin>>t;
	while (t--){
		solve();
	}
	return 0;
}
posted @ 2024-02-24 14:25  SFlyer  阅读(76)  评论(0编辑  收藏  举报