2021牛客暑期多校训练营7 部分题解

F.xay loves trees

  • 题意
    给你两个具有 n n n个结点的且树根编号为 1 1 1的无向树,需要你找到一个最大的顶点集使得其在第一颗树上任意两点是父子关系,即连通;在第二颗树上任意两点都不是父子关系,即任意两点均不连通。

  • 解题思路
    c f cf cf某场 d i v 1 div1 div1 C C C题差不多:https://codeforces.com/problemset/problem/1528/C待补。

  • 逆十字大佬代码

#include<bits/stdc++.h>
using namespace std;

vector<int> v1[300010],v2[300010];
int T,n,x,y,dep[300010],rt[300010],tot,L[300010],R[300010],ans;
struct node{int ls,rs,ma,laz;}t[25000010];

void getdfn(int x,int fa=0)
{
	L[x]=++tot;
	for (int i=0,sz=v2[x].size(); i<sz; i++)
		if (v2[x][i]!=fa) getdfn(v2[x][i],x);
	R[x]=tot;
}

void pushdown(int i)
{
	if (!t[i].ls) t[i].ls=++tot;
	if (!t[i].rs) t[i].rs=++tot;
	if (!t[i].laz) return;
	t[t[i].ls].ma=t[t[i].ls].laz=t[i].laz;
	t[t[i].rs].ma=t[t[i].rs].laz=t[i].laz;
	t[i].laz=0;
}

int add(int i,int I,int l,int r,int ql,int qr,int v)
{
	t[i].ma=v;
	if (l==ql&&r==qr) 
	{
		int nw=v-t[I].ma;
		t[i].ls=t[i].rs=0;
		t[i].laz=v;
		return nw;
	}
	int mid=(l+r)>>1;
	pushdown(I);
	if (qr<=mid) return t[i].rs=t[I].rs,add(t[i].ls=++tot,t[I].ls,l,mid,ql,qr,v);
	if (ql>mid) return t[i].ls=t[I].ls,add(t[i].rs=++tot,t[I].rs,mid+1,r,ql,qr,v);
	return min(add(t[i].ls=++tot,t[I].ls,l,mid,ql,mid,v),add(t[i].rs=++tot,t[I].rs,mid+1,r,mid+1,qr,v));
}

void dfs(int x,int fa,int la)
{
	dep[x]=dep[fa]+1,rt[x]=++tot;
	la=min(la+1,add(rt[x],rt[fa],1,n,L[x],R[x],dep[x]));
	ans=max(ans,la);
	for (int i=0,sz=v1[x].size(); i<sz; i++)
		if (v1[x][i]!=fa) dfs(v1[x][i],x,la);
}

int main()
{
	scanf("%d",&T);
	while (T--)
	{
		scanf("%d",&n);
		for (int i=1; i<=n; i++) v1[i].clear(),v2[i].clear();
		for (int i=1; i<n; i++) scanf("%d%d",&x,&y),v1[x].push_back(y),v1[y].push_back(x);
		for (int i=1; i<n; i++) scanf("%d%d",&x,&y),v2[x].push_back(y),v2[y].push_back(x);
		tot=0,getdfn(1),tot=0,dep[0]=0,ans=0,dfs(1,0,10);
		for (int i=1; i<=tot; i++) t[i].ls=t[i].rs=t[i].ma=t[i].laz=0;
		printf("%d\n",ans);
	}
	return 0;
}

H.xay loves count

  • 题意
    给你一个序列 a a a,找出符合 a i × a j = a k a_i\times a_j=a_k ai×aj=ak ( i , j , k ) (i,j,k) (i,j,k)元组数。

  • 解题思路
    我们可以统计每个元素出现的次数以及得到去重后的 n u m num num数组,这样,我们只需暴力枚举 n u m num num数组找 a i , a j a_i,a_j ai,aj了,方案数即是 c n t [ a i ] × c n t [ a j ] × c n t [ a i × a j ] cnt[a_i]\times cnt[a_j]\times cnt[a_i\times a_j] cnt[ai]×cnt[aj]×cnt[ai×aj],由于 a i ≤ 1 e 6 a_i \leq 1e6 ai1e6,故两个数相乘超过 1 e 6 1e6 1e6即不符合,容易证明,在极端情况下,即 n = 1 e 6 , a i = i n=1e6,a_i=i n=1e6,ai=i时,我们需要计算 1 e 6 1 + 1 e 6 2 + . . . + 1 e 6 n \frac{1e6}{1}+\frac{1e6}{2}+...+\frac{1e6}{n} 11e6+21e6+...+n1e6,复杂度为 O ( n l o g n ) O(nlogn) O(nlogn),可以通过。

  • AC代码

/**
  *@filename:H
  *@author: pursuit
  *@created: 2021-08-07 12:23
**/
#include <bits/stdc++.h>
#define debug(a) cout << "debug : " << (#a)<< " = " << a << endl;

using namespace std;

typedef pair<int,int> pii;
typedef long long ll;
const int N = 1e6 + 10;
const int P = 1e9 + 7;
const int INF = 0x3f3f3f3f;

int n,x;
int num[N],tot,cnt[N];
void solve(){
    ll ans = 0;
    sort(num + 1,num + 1 + tot);
    for(int i = 1; i <= tot; ++ i){
        for(int j = 1; j <= tot; ++ j){
            if(1LL * num[i] * num[j] > 1e6)break;
            ans += 1LL * cnt[num[i] * num[j]] * cnt[num[i]] * cnt[num[j]]; 
        }
    }
    printf("%lld\n", ans);
}
int main(){	
    scanf("%d", &n);
    for(int i = 1; i <= n; ++ i){
        scanf("%d", &x);
        if(!cnt[x]){
            num[++ tot] = x;
        }
        cnt[x] ++;
    }
    solve();
    return 0;
}

I.xay loves or

  • 题意
    给你两个整数 x , s x,s x,s,需要找到有多少满足条件的正整数 y y y 使得 x   o r   y = s x\ or\ y =s x or y=s

  • 解题思路
    根据 o r or or性质,每位上两者有一个为 1 1 1则为 1 1 1,都为 0 0 0才为 0 0 0,据此可知当 x x x s s s i i i位上都为 1 1 1,那么 y y y的第 i i i位可以取 0 0 0 1 1 1。当 s s s的第 i i i位为 0 0 0,而 x x x的第 i i i位为 1 1 1则不可能,而剩下的情况 y y y的第 i i i位只有一种取值。需要注意,特判 x = s x=s x=s,此时 y = 0 y=0 y=0我们也会统计进去,而由于 y > 0 y>0 y>0,故我们需要减去这种情况。

  • AC代码

/**
  *@filename:I
  *@author: pursuit
  *@created: 2021-08-07 12:04
**/
#include <bits/stdc++.h>
#define debug(a) cout << "debug : " << (#a)<< " = " << a << endl;

using namespace std;

typedef pair<int,int> pii;
typedef long long ll;
const int N = 1e5 + 10;
const int P = 1e9 + 7;
const int INF = 0x3f3f3f3f;

int x,s;
void solve(){
    ll ans = 1;
    bool flag = false;
    for(int i = 31; i >= 0; -- i){
        int u = (s >> i) & 1, v = (x >> i) & 1;
        if(u == 0 && v == 1){
            flag = true;
            break;
        }
        else if(u == 1 && v == 1){
            ans *= 2;
        }
    }
    if(x == s)ans -= 1;
    if(flag)ans = 0;
    cout << ans << endl;
}
int main(){
    cin >> x >> s;	
    solve();
    return 0;
}
posted @ 2022-03-26 16:48  unique_pursuit  阅读(31)  评论(0)    收藏  举报