2021牛客暑期多校训练营7

2021牛客暑期多校训练营7

文章目录

  • 2021牛客暑期多校训练营7
    • F:xay_loves_trees
      • 解释
      • 代码
    • H:xay_loves_count
      • 解释
      • 代码
    • I:xay_loves_or
      • 解释
      • 代码

F:xay_loves_trees

解释

思考对于第一棵树,当dfs遍历时以u为最深节点,判断它最多能往回走多高(h + 1),那么此时形成的连续链大小为 depth - h。

对于第二棵树,处理好dfs序,一棵树父亲节点的dfs序区间一定包含子树。

对于第一棵树,dfs遍历,当处理到u节点时,先询问它儿子节点的最大值,存入h数组。

然后将它所有的儿子节点,都赋值为depth(u),此时节点的深度,表示这些节点的最近祖先为u。

之后再dfs,维护一条链,dfs到u节点时,维护所有这条链中h的最大值(maxx)。答案为(depth(u) - maxx).

最后取最大值就行了。

上述操作中,维护一个节点所有子节点的值用主席树+标记永久化维护。

代码

#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#include
using namespace std;
const int N = 3e5 + 10;
//#define int long long
typedef __int128 lll;
typedef long long ll;

vector<int> g1[N],g2[N];
int n;

// 主席树部分
int rt[N];

#define ls(x) t[x].ls
#define rs(x) t[x].rs
#define d(x) t[x].d
#define lazy(x) t[x].lazy

struct LSegmentTree{
	int ls,rs,d;
	int lazy;
}t[N << 5];
int LS_idx = 0;

int update(int p,int l,int r,int ql,int qr,int val){
	int root = ++LS_idx;
	ls(root) = ls(p),rs(root) = rs(p),d(root) = val;
	if(ql <= l && qr >= r){
		lazy(root) = val;
		return root;
	}
	int mid = (l + r) >> 1;
	if(ql <= mid) ls(root) = update(ls(root),l,mid,ql,qr,val);
	if(qr > mid) rs(root) = update(rs(root),mid+1,r,ql,qr,val);
	return root;
}

int query(int p,int l,int r,int ql,int qr){
	int ans = lazy(p);
	if(ql <= l && qr >= r) return max(ans,d(p));
	int mid = (l + r) >> 1;
	if(ql <= mid) ans = max(ans,query(ls(p),l,mid,ql,qr));
	if(qr > mid) ans = max(ans,query(rs(p),mid+1,r,ql,qr));
	return ans;
}

// dfs序 
int L[N],R[N],tim;

void dfs_dfn(int u,int fa){
	L[u] = ++tim;
	for(auto j : g2[u]){
		if(j == fa) continue;
		dfs_dfn(j,u);
	}
	R[u] = tim;
}

// dfs遍历第一棵树 
int depth[N],h[N];

void dfs(int u,int fa){
	depth[u] = depth[fa] + 1;
	h[u] = query(rt[fa],1,n,L[u],R[u]);
	rt[u] = update(rt[fa],1,n,L[u],R[u],depth[u]);
	for(auto j : g1[u]){
		if(j == fa) continue;
		dfs(j,u);
	}
} 

int dfs_ans(int u,int fa,int maxdepth){
	int nowmaxdepth = max(maxdepth,h[u]);
	int ans = depth[u] - nowmaxdepth;
	for(auto j : g1[u]){
		if(j == fa) continue;
		ans = max(ans,dfs_ans(j,u,nowmaxdepth));
	}
	return ans;
}

void init(){
	for(int i=1;i<=n;i++) g1[i].clear(),g2[i].clear();
	for(int i=0;i<=LS_idx;i++) rt[i] = ls(i) = rs(i) = d(i) = lazy(i) = 0;
	tim = LS_idx = 0;
}

signed main(){
	IOS
    int tt; cin>>tt;
    while(tt --){
    	cin>>n;
    	init();
    	for(int i=1;i<n;i++){
    		int a,b; cin>>a>>b;
    		g1[a].push_back(b);
    		g1[b].push_back(a);
		}
		for(int i=1;i<n;i++){
    		int a,b; cin>>a>>b;
    		g2[a].push_back(b);
    		g2[b].push_back(a);
		}
		dfs_dfn(1,0); dfs(1,0);
		cout<<dfs_ans(1,0,0)<<endl;
	}
	return 0;
}

H:xay_loves_count

解释

枚举确定 a i a_i ai 后,枚举 a j , a j a_j,a_j aj,aj的范围是 1 e 6 a i \frac{1e6}{a_i} ai1e6 , 那么总时间复杂度为 ∑ 1 1 e 6 1 e 6 i \sum_{1}^{1e6}\frac{1e6}{i} 11e6i1e6 , O ( n l o g n ) O(nlogn) O(nlogn)

代码

#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#include
using namespace std;
const int N = 1e6 + 10;
//#define int long long
typedef long long ll;

int cnt[N];

signed main(){
	IOS
    int n,maxx = 0; cin>>n;
	for(int i=1,a;i<=n;i++) cin>>a,cnt[a]++,maxx = max(maxx,a);
	ll ans = 0;
    for(int i=1;i<=maxx;i++)
    	for(int j=1;i*j<=maxx;j++)
    		ans += cnt[i] * cnt[j] * cnt[j*i];
    cout<<ans<<endl;
	return 0;
}

I:xay_loves_or

解释

可以发现,只需要枚举s中所有出现的1的数,和x中出现1的数

  1. 若x出现1的位置而s没出现,则无解
  2. 对于所有出现1的相同的位置(cnt),y可以选择是否选择出现有 2 c n t 2^{cnt} 2cnt种方案
  3. 因为要求正数,所以当 x = = s x == s x==s 时,去掉 y == 0的方案。

代码

#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#include
using namespace std;
#define int long long
const int N = 5e3 + 10;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
typedef long long ll;

int qmi(int a,int b){
	int res = 1;
	while(b){
		if(b & 1) res = res * a;
		a = a * a;
		b >>= 1;
	}
	return res;
}

signed main(){
	IOS
    int x,s; cin>>x>>s;
    map<int,int> mp;
    bool plas = true;
    for(int i=0;(s >> i);i++){
    	int j = (s >> i) & 1;
    	if(j) mp[i] = 1;
	}
	int cnt = 0;
    for(int i=0;(x >> i);i++){
    	int j = (x >> i) & 1;
    	if(j){
    		if(!mp[i]){
    			plas = false;
			}else cnt ++;
		}
	}
	if(!plas) cout<<0<<endl;
	else{
		int ans = qmi(2,cnt);
		if(x == s) ans --;
		cout<<ans<<endl;
	}
	return 0;
}

你可能感兴趣的:(2021多校,算法)