省选模拟30

A. T1

首先考虑如何计算一种序列的子序列异或和的总和

位运算所以考虑按位考虑

那么这一位的值只和选择奇数次的方案有关

简单写个暴力,发现只要这一位有值他就和对答案产生贡献

那么问题就变成了 \(n\) 个数,每个数都在 \(l\)\(r\) 之间,或起来的值不同的个数

发现 \(n\geq 2\) 时答案都和 \(n=2\) 的一样,所以将 \(n=1\) 判掉,答案就是 \(r-l+1\)

由于是或运算,所以答案只会变大,不会变小,然后你考虑构造或起来大于 \(r\) 的方法

再找到第一个不一样的位置后,把前面都先去掉

发现可以将 \(r\) 先从 \(100100\) 补成 \(100111\) ,也就是从高到低第二个 \(1\) 后面全都是 \(1\) 的形式

然后考虑用 \(100000\)\(011111\) 一直到 \(l\) 的值全部去或,跟 \(r\) 判断一下就知道增加了多少

Code
#include<bits/stdc++.h>
#define int long long//OVERFLOW !!! MEMORY LIMIT !!!
#define rint signed
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
inline int read(){
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
int T,n,l,r,ans,U;
int mxr,mxl,res,ccc;
inline void solve(){
	n=read(),l=read(),r=read();
	if(n==1) return printf("%lld\n",r-l+1),void();
	if(l==r) return printf("%lld\n",1ll),void();
	ans=r-l+1;
	for(int i=0;i<=60;i++) if((r>>i)&1) mxr=i;
	for(int i=0;i<=60;i++) if((l>>i)&1) mxl=i;
	while(mxr&&mxl&&mxr==mxl){
		r-=1ll<<mxr;l-=1ll<<mxl;mxr=mxl=0;
		for(int i=0;i<=60;i++) if((r>>i)&1) mxr=i;
		for(int i=0;i<=60;i++) if((l>>i)&1) mxl=i;
	}
	ccc=r-(1ll<<mxr);U=1;while(U<ccc) U=U<<1|1;
	if(ccc){ans+=((1ll<<mxr)+U)-r;r=(1ll<<mxr)+U;}
	res=1ll<<mxr;res=res-max(r-res+1,l);ans+=res;
	printf("%lld\n",ans);
}
signed main(){
#ifdef LOCAL
	freopen("in","r",stdin);
	freopen("out","w",stdout);
#endif
	freopen("a.in","r",stdin);
	freopen("a.out","w",stdout);
	T=read();while(T--) solve();
	return 0;
}

B. T2

任意 \(4\) 个叶子有且仅有 \(1\) 种划分方案,于是一颗树就有 \(\binom{n}{4}\) 种方案

划分方案就类似与用两条互不相交的链,分别将 \(A,B\)\(C,D\) 链接起来

然后两条链之间又有一条链,于是考虑容斥,枚举删掉一个点还是一条边

那么答案就是删边得到的答案减去删点得到的答案

考虑去掉交集来求对称差

于是先在第一颗树里枚举删除的边或者点,然后再在第二颗树里去求答案,再乘上容斥系数

具体就是用第一颗树里枚举删除的边或点,对剩下的点染色

然后再在第二颗树里去求答案,枚举删除边或者点,再枚举子树内同色的点去求方案

换一下根就能做到 \(O(n^2)\)

Code
#include<bits/stdc++.h>
#define int long long//OVERFLOW !!! MEMORY LIMIT !!!
#define rint signed
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
inline int read(){
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
int n,ans,res;
int col[2010];
int C[2010][2010];
int siz[2010][5];
namespace t2{
	vector<int>g[2010];
	inline void add(int x,int y){g[x].emplace_back(y);}
	void dfs1(int x,int fa){
		for(int i=1;i<=3;i++) siz[x][i]=0;siz[x][col[x]]=1;
		for(auto y:g[x]) if(y!=fa){
			dfs1(y,x);
			for(int i=1;i<=3;i++) siz[x][i]+=siz[y][i];
		}
	}
	void dfs2(int x,int fa){
		int tmp[5];for(int i=1;i<=3;i++) tmp[i]=siz[x][i];
		if(fa){
			for(int i=1;i<=3;i++) siz[x][i]-=siz[fa][i];
			for(int i=1;i<=3;i++) for(int j=1;j<=3;j++) if(i!=j){
				if(siz[x][i]&&siz[fa][j]) res+=(siz[x][i]*(siz[x][i]-1)/2)*(siz[fa][j]*(siz[fa][j]-1)/2);
			}
			for(int i=1;i<=3;i++) siz[x][i]+=siz[fa][i];
		}
		for(int i=1;i<=3;i++) for(int j=1;j<=3;j++) if(i!=j){
			for(auto y1:g[x]) for(auto y2:g[x]) if(y1<y2){
				if(siz[y1][i]&&siz[y2][j]) res-=(siz[y1][i]*(siz[y1][i]-1)/2)*(siz[y2][j]*(siz[y2][j]-1)/2);
			}
		}
		for(auto y:g[x]) if(y!=fa){
			for(int i=1;i<=3;i++) siz[x][i]=tmp[i];
			for(int i=1;i<=3;i++) siz[x][i]-=siz[y][i];
			for(int i=1;i<=3;i++) siz[y][i]+=siz[x][i];
			dfs2(y,x);
		}
	}
}
namespace t1{
	vector<int>g[2010];
	inline void add(int x,int y){g[x].emplace_back(y);}
	void dfs2(int x,int fa,int c){
		if(x<=n) col[x]=c;
		for(auto y:g[x]) if(y!=fa) dfs2(y,x,c);
	}
	void dfs1(int x,int fa){
		if(fa){
			dfs2(x,fa,1);dfs2(fa,x,2);res=0;
			t2::dfs1(n+1,0);t2::dfs2(n+1,0);
			ans+=res;
		}
		int C=0;for(auto y:g[x]) dfs2(y,x,++C);res=0;
		t2::dfs1(n+1,0);t2::dfs2(n+1,0);ans-=res;
		for(auto y:g[x]) if(y!=fa) dfs1(y,x);
	}
}
signed main(){
#ifdef LOCAL
	freopen("in","r",stdin);
	freopen("out","w",stdout);
#endif
	freopen("b.in","r",stdin);
	freopen("b.out","w",stdout);
	n=read();
	for(int i=1,x,y;i<=2*n-3;i++){x=read(),y=read();t1::add(x,y);t1::add(y,x);}puts("");
	for(int i=1,x,y;i<=2*n-3;i++){x=read(),y=read();t2::add(x,y);t2::add(y,x);}
	for(int i=0;i<=1000;i++){C[i][0]=1;for(int j=1;j<=i;j++) C[i][j]=C[i-1][j-1]+C[i-1][j];}
	t1::dfs1(n+1,0);
	ans=2*C[n][4]-ans*2;
	printf("%lld\n",ans);
	return 0;
}

C. T3

咕咕咕

posted @ 2022-03-12 20:39  Max_QAQ  阅读(62)  评论(0)    收藏  举报