Codeforces Round #695 (Div. 2)


菜死了


A. Wizard of Orz

贪心,肯定最高位越高越好,所以显然最高位为9,然后需要考虑从那个位开始时最优的,接着考虑次高位,根据贪心原则,次高位最优是8,即从此高位开始停止,其他情况都不是最优。

B. Hills And Valleys

枚举每个位置修改为前一个和后一个数的最大贡献。

C. Three Bags

贪心,最后只剩两类情况:1.两个集合求和减去另一个集合。2.三个集合之和减去(两个集合的最小值的两倍)。

D. Sum of Paths

d p dp dp,设 d p [ i ] [ j ] dp[i][j] dp[i][j]表示走 i i i步到 j j j的方案数,初始化 d p [ 0 ] [ i ] = 1 dp[0][i]=1 dp[0][i]=1,然后求和对于位置 j j j,计算出位置 j j j的贡献次数: c n t [ j ] = ∑ i = 0 k d p [ i ] [ j ] × d p [ k − i ] [ j ] cnt[j]=\sum\limits_{i=0}^k dp[i][j]\times dp[k-i][j] cnt[j]=i=0kdp[i][j]×dp[ki][j]

E. Distinctive Roots in a Tree

树上差分,考虑对于当前结点的子树,如果上方有与该结点权相同的结点,说明该子树都不可能,然后分别考虑该结点的每个儿子子树,如果儿子子树有与该节点相同的点权,说明其他儿子子树不成立(因为其他子树必须经过根然后到该子树),显然上方子树也不成立,只有该儿子子树的结点可能成立,因为 d f s dfs dfs的原因,所以该儿子子树的情况我们是知道的,所以我们只需先让所有标记加1,然后该儿子子树标记减1,加1表示不成立,这样儿子子树不成立的还是不成立,成立的也不会影响。差分的话就离散化+ d f n dfn dfn序。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+5,M=2e4+5,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a,b) memset(a,b,sizeof a)
#define PII pair<int,int>
#define fi first
#define se second
#define pb push_back
int n,a[N],b[N],s[N],dfn[N],sz[N],sum[N],cnt,tot[N];
vector<int>e[N];
void upd(int l,int r,int k){
	if(l>r) return;
	s[l]+=k,s[r+1]-=k;
}k,km
void dfs(int u,int fa){
	sz[u]=1,dfn[u]=++cnt;
	int temp=sum[a[u]];++sum[a[u]];
	for(int v:e[u]){
		if(v==fa) continue;
		int tmp=sum[a[u]];
		dfs(v,u),sz[u]+=sz[v];
		if(sum[a[u]]>tmp){
			upd(1,n,1);
			upd(dfn[v],dfn[v]+sz[v]-1,-1);
		} 
	}
	temp=sum[a[u]]-temp;
	if(temp<tot[a[u]]) upd(dfn[u],dfn[u]+sz[u]-1,1);
}
int main(){
	scanf("%d",&n);for(int i=1;i<=n;i++) scanf("%d",&a[i]),b[i]=a[i];sort(b+1,b+n+1);
	int m=unique(b+1,b+n+1)-b-1;for(int i=1;i<=n;i++) a[i]=lower_bound(b+1,b+m+1,a[i])-b,tot[a[i]]++;
	for(int i=1,u,v;i<n;i++) scanf("%d%d",&u,&v),e[u].pb(v),e[v].pb(u);
	dfs(1,0);int ans=0;
	for(int i=1;i<=n;i++){
		s[i]+=s[i-1];
		if(!s[i]) ans++;
	}printf("%d\n",ans);
	return 0;
}