ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【考试总结】2022-06-10

2022-06-12 11:32:12  阅读:93  来源: 互联网

标签:10 06 sub int auto mid ckmax 2022 id


Geometric Progressions

将所有 \(a_i,b_i\) 中出现过的质因子取出,并从 \(1\) 到 \(n\) 考察每对 \((a_i,b_i)\) 对这些因子取值的影响

求出来 \((a,b)\) 在每个因子指数上的直线表达式 \(kx+b\) 并取 \(x\ge 0\) 时的交集,如果出现某个质因子交集为空那么不合法,否则最小答案中每个质因子指数就是将其对应直线的 \(x\) 带入 \(0\) 得到

设之前已经合并的结果中每个因子的直线为 \(fk_ix+fb_i\),而当前待合并的直线表达式为 \(gk_i+gb_i\)

若 \(fk_i,gk_i\) 两者为 \(0\) 则看 \(fb_i\) 是否等于 \(gb_i\);有其中一个为 \(0\) 那么可以得到 \(x\) 的具体值,不是整数显然不合法,否则合并结果中每个质因子的直线斜率都是 \(0\),对应的纵轴截距可以带入得到的 \(x\) 求出

如果两者均不是 \(0\) 那么得到方程 \(fk_ix_1+fb_i=gk_ix_2+gb_i\) ,合并后的结果就是这个方程的解集

由于每个质因子都可能得到这样一个方程,如果方程数量超过 \(1\) 那么可以得到 \(x\) 的具体值或者判定无解

如果只有一个方程,剩下的本质相同那么可以使用 \(\text{exgcd}\) 得到新的解集,要求纵轴截距最小 和 求方程在两个变量都非负的情况下 \(x_1\) 最小一致,得到最小的 \(x_1\) 之后可以计算出来新的直线

Code Display
const int N=1e5+10;
int pri[N],num;
inline void Divide(int x){
	for(int i=2;i*i<=x;++i){
		if(x%i) continue;
		while(x%i==0) x/=i;
		pri[++num]=i;
	}
	if(x>1) pri[++num]=x;
	return ;
}
inline void exgcd(int a,int b,int &x,int &y){
	if(!b) return x=1,y=0,void();
	exgcd(b,a%b,x,y);
	int k=x; x=y; y=k-(a/b)*x;
	return ;
}
struct line{int k,b;}f[N],g[N];
struct Equation{
	int A,B,C;
	inline void adjust(){
		int g=__gcd(myabs(A),__gcd(myabs(B),myabs(C)));
		A/=g; B/=g; C/=g;
		return ;
	}
};
inline void solve(int K,int B,int id){
	for(int i=1;i<=num;++i){
		g[i].k=g[i].b=0;
		while(K%pri[i]==0) g[i].k++,K/=pri[i];
		while(B%pri[i]==0) g[i].b++,B/=pri[i];
	}
	if(id==1){
		rep(i,1,num) f[i]=g[i];
		return ;
	}
	int Turn=3;
	while(Turn--){
		for(int i=1;i<=num;++i){
			if(!g[i].k&&!f[i].k){
				if(g[i].b!=f[i].b) puts("-1"),exit(0);
				continue;
			}
			if(!g[i].k){
				if(g[i].b<f[i].b) puts("-1"),exit(0);
				if((g[i].b-f[i].b)%f[i].k) puts("-1"),exit(0);
				int x=(g[i].b-f[i].b)/f[i].k;
				for(int j=1;j<=num;++j) f[j].b=f[j].k*x+f[j].b,f[j].k=0;
				continue;
			}
			if(!f[i].k){
				if(f[i].b<g[i].b) puts("-1"),exit(0);
				if((f[i].b-g[i].b)%g[i].k) puts("-1"),exit(0);
				int x=(f[i].b-g[i].b)/g[i].k;
				for(int j=1;j<=num;++j) g[j].b=g[j].k*x+g[j].b,g[j].k=0;
			}
		}
	}
	
	Equation F;
	int mark=0,X=-1,Y=-1;
	for(int i=1;i<=num;++i){
		if(!(g[i].k*f[i].k)) continue;
		if(!mark){
			F.A=f[i].k; F.B=-g[i].k; F.C=g[i].b-f[i].b;
			mark=1;
			continue;
		}
		int A=f[i].k,B=-g[i].k,C=g[i].b-f[i].b;
		if(mark==1){
			int G=__gcd(myabs(A),myabs(F.A));
			int dcur=A/G,dF=F.A/G;
			F.A*=dcur; F.B*=dcur; F.C*=dcur;
			A*=dF; B*=dF; C*=dF;
			if(A==F.A&&B==F.B){
				if(C!=F.C) puts("-1"),exit(0);
				F.adjust();
				continue;
			}
			C-=F.C; B-=F.B;
			if(C*B<0) puts("-1"),exit(0);
			if(C<0) C=-C,B=-B;
			if(C%B) puts("-1"),exit(0);
			Y=C/B;
			if((F.C-Y*F.B)%F.A) puts("-1"),exit(0);
			X=(F.C-Y*F.B)/F.A;
			if(X<0) puts("-1"),exit(0);
			mark=2;
			continue;
		}
		if(A*X+B*Y!=C) puts("-1"),exit(0);
	}
	if(mark==2){
		for(int i=1;i<=num;++i) f[i].b+=f[i].k*X,f[i].k=0;
		return ;
	}
	if(!mark) return ;
	F.B*=-1;
	int G=__gcd(F.A,F.B);
	if(F.C%G) puts("-1"),exit(0);
	F.A/=G; F.B/=G; F.C/=G;
	int x,y;
	exgcd(F.A,F.B,x,y);
	x*=F.C; y*=-F.C;
	int dx=0,dy=0;
	if(x<0) dx=-((-x+F.B-1)/F.B);
	else dx=x/F.B;
	if(y<0) dx=-((-y+F.A-1)/F.A);
	else dy=y/F.A;
	x-=F.B*min(dx,dy);
	y-=F.A*min(dx,dy);
	for(int i=1;i<=num;++i){
		f[i].b+=f[i].k*x;
		f[i].k*=F.B;
	}
	return ;
}
int a[110],b[110],n;
signed main(){
	freopen("a.in","r",stdin); freopen("a.out","w",stdout);
	n=read();
	for(int i=1;i<=n;++i){
		a[i]=read(),b[i]=read();
		Divide(a[i]);
		Divide(b[i]);
	}
	sort(pri+1,pri+num+1);
	num=unique(pri+1,pri+num+1)-pri-1;
	for(int i=1;i<=n;++i) solve(b[i],a[i],i);
	int ans=1;
	for(int i=1;i<=num;++i) ckmul(ans,ksm(pri[i],f[i].b));
	printf("%lld\n",(long long)ans);
	return 0;
}


Bichrome Spanning Tree

求出任一 \(\rm MST\),设其权值总和为 \(S\),如果 \(x<S\) 无解

先强制 \(\rm MST\) 上所有边的颜色都一样,这个 \(\text{case}\) 方案数要乘 \(2\)

那么对于一条非树边,如果将其加入后带来的最小增量小于 \(x-S\) ,那么它的颜色和 \(\rm MST\) 上边的颜色保持一致;记录增量等于 \(x-S\) 的边的数量 \(e_1\) 和增量大于 \(x-S\) 的边的数量 \(e_2\)

注意到 \(e_2\) 中的每条可以随便选择,而 \(e_1\) 中有一条和 \(\rm MST\) 上钦定的颜色不一样即可,方案数就是 \(2(2^{e_1}-1)2^{e_2}\)

如果 \(x=S\) 还可以将 \(\rm MST\) 上的边染成不一样的颜色,其它边的颜色不再重要,方案数是 \((2^{n-1}-2)2^{m-n+1}\)

求增量使用倍增,复杂度 \(\Theta((n+m)\log n)\)

Code Display
const int N=2010;
struct edge{int u,v,w;}e[N];
struct DSU{
	int fa[N];
	inline void init(int n){rep(i,1,n) fa[i]=i; return ;}
	inline int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
	inline void merge(int x,int y){fa[find(x)]=find(y); return ;}
}Dsu;
int n,m,X;
bool mark[N];
signed main(){
	freopen("b.in","r",stdin); freopen("b.out","w",stdout);
	n=read(); m=read(); X=read(); 
	for(int i=1;i<=m;++i) e[i].u=read(),e[i].v=read(),e[i].w=read();
	sort(e+1,e+m+1,[&](const edge a,const edge b){return a.w<b.w;});
	Dsu.init(n);
	vector<int> dep(n+1),val(n+1),fa(n+1);
	vector<vector<pair<int,int> > >G(n+1);
	int sum=0;
	for(int i=1;i<=m;++i){
		int x=Dsu.find(e[i].u),y=Dsu.find(e[i].v);
		if(x==y) continue;
		mark[i]=1;
		Dsu.merge(x,y);
		G[e[i].u].emplace_back(e[i].v,e[i].w);
		G[e[i].v].emplace_back(e[i].u,e[i].w);
		sum+=e[i].w;
	}
	if(X<sum) puts("0"),exit(0);
	function<void(int,int)>dfs=[&](int x,int fat){
		dep[x]=dep[fa[x]=fat]+1;
		for(auto e:G[x]){
			int t=e.fir; if(t==fat) continue;
			val[t]=e.sec;
			dfs(t,x);
		}
	};
	dfs(1,0);
	auto calc_max=[&](int u,int v){
		int res=0;
		if(dep[u]>dep[v]) swap(u,v);
		while(dep[u]<dep[v]) res=max(res,val[v]),v=fa[v];
		if(u==v) return res;
		while(u!=v){
			res=max(res,val[u]); u=fa[u];
			res=max(res,val[v]); v=fa[v];
		}
		return res;
	};
	int cnt_sam=0,cnt_lar=0;
	for(int i=1;i<=m;++i) if(!mark[i]){
		int w=calc_max(e[i].u,e[i].v);
		if(e[i].w-w>X-sum) cnt_lar++;
		else if(e[i].w-w==X-sum) cnt_sam++;
	}
	int ans1=del(ksm(2,cnt_lar+cnt_sam+1),ksm(2,cnt_lar+1)),ans2=del(ksm(2,m),ksm(2,m-n+2));

	if(sum==X) printf("%lld\n",add(ans1,ans2));
	else printf("%lld\n",ans1);
	return 0;
}


Network

建立点分树,求出来子联通块中每个点到联通块的路径上边权最大最小值 \((l,r)\) 并提前排序,同时求出来 \(f_i\) 表示现在的服务器中到 \(i\) 的最大的 \(r-l\)

二分答案,每次根据点分树上维护的信息判断哪些点不能成为被改变的点

对于每个分治重心,如果利用同一棵子树中的点判定另一个点不合法是不劣的,因为极值的差不会变小

先倒序扫描当前某个子联通块根处排好序的信息,并维护一个单调队列,其中包含使用 \(l\) 获得极值和使用 \(r\) 获得极值的限制,并且都是升序排序

如果当前元素能满足队尾的使用 \(r-mid\) 获得极值的限制可以弹出,不能弹出者中如果存在 \(l+mid\) 大于当前 \(r\) 的情况则当前元素不合法,注意联通块的根也可能造成当前元素不合法

如果当前元素需要其它元素的改变来满足 \(mid\) 的限制那么将其加入单调队列,由于是倒序扫描数组,那么可以对队首进行更新

之后正序扫描,这次以判定 \(r-mid\) 是否 \(<l\) 作为标准即可,过程和上面的类似

时间复杂度 \(\Theta(n\log n\log V)\)

Code Display
const int N=1e5+10;
int n,typ[N];
vector<pair<int,int> >G[N];
int rt,cursum,siz[N],ff[N];
bool vis[N];
inline void findrt(int x,int fat){
	ff[x]=0; siz[x]=1;
	for(auto e:G[x]){
		int t=e.fir; if(vis[t]||t==fat) continue;
		findrt(t,x);
		siz[x]+=siz[t];
		ckmax(ff[x],siz[t]);
	}
	ckmax(ff[x],cursum-siz[x]);
	if(ff[x]<ff[rt]) rt=x;
	return ;
}
int f[N];
vector<tuple<int,int,int> >inter[N];
inline void build(int x){
	vis[x]=1;
	vector<vector<tuple<int,int,int> > >tmp;
	vector<tuple<int,int,int> > sub;
	function<void(int,int,int,int)>dfs=[&](int x,int fat,int Mn,int Mx){
		sub.emplace_back(Mn,Mx,x);
		for(auto e:G[x]){
			int t=e.fir; if(vis[t]||t==fat) continue;
			dfs(t,x,min(Mn,e.sec),max(Mx,e.sec));
		}
		return ;
	};
	for(auto e:G[x]){
		int t=e.fir; if(vis[t]) continue;
		sub.clear();
		dfs(t,x,e.sec,e.sec);
		tmp.emplace_back(sub);
	}
	int minl=1e9,maxr=0,mxlen=0;
	for(auto &sub:tmp){
		for(auto a:sub){
			int id,L,R; tie(L,R,id)=a;
			if(typ[id]) continue;
			ckmax(f[id],max({R-minl,maxr-L,mxlen}));
			if(maxr||typ[x]) ckmax(f[id],R-L);
		}
		for(auto a:sub){
			int id,L,R; tie(L,R,id)=a;
			if(!typ[id]) continue;
			ckmax(maxr,R);
			ckmin(minl,L);
			ckmax(mxlen,R-L);
		}
	}
	reverse(tmp.begin(),tmp.end());
	minl=1e9; maxr=mxlen=0;
	for(auto &sub:tmp){
		for(auto a:sub){
			int id,L,R; tie(L,R,id)=a;
			if(typ[id]) continue;
			ckmax(f[id],max({R-minl,maxr-L,mxlen}));
			if(maxr||typ[x]) ckmax(f[id],R-L);
		}
		for(auto a:sub){
			int id,L,R; tie(L,R,id)=a;
			if(!typ[id]) continue;
			ckmax(maxr,R);
			ckmin(minl,L);
			ckmax(mxlen,R-L);
		}
	}
	if(!typ[x]) ckmax(f[x],mxlen);
	for(auto &sub:tmp){
		for(auto a:sub){
			int id=get<2>(a);
			if(!typ[id]) inter[x].emplace_back(a);
		}
	}
	sort(inter[x].begin(),inter[x].end());
	for(auto e:G[x]){
		int t=e.fir; if(vis[t]) continue;
		cursum=siz[t]; rt=0;
		findrt(t,0);
		build(rt);
	}
}
bool legal[N];
inline void solve(int x,int mid){
	deque<pair<int,int> >q;
	int minr=1e9;
	for(auto iter=inter[x].rbegin();iter!=inter[x].rend();++iter){
		int l,r,id; tie(l,r,id)=*iter;
		while(q.size()&&q.back().first>=l) q.pop_back();
		if(r-l<mid && q.size() && r<q.back().second) legal[id]=0;
		if(!typ[x] && f[x]<mid && r-l<mid) legal[id]=0; 
		if(f[id]<mid&&r<=minr){
			minr=r;
			while(q.size() && q.front().sec<l+mid) q.pop_front();
			q.push_front({r-mid,l+mid});
		}
	}
	q.clear();
	for(auto iter:inter[x]){
		int l,r,id; tie(l,r,id)=iter;
		while(q.size()>=2&& q[1].first<l) q.pop_front();
		if(r-l<mid && !q.empty() && q.front().sec>r && q.front().fir<l){
			legal[id]=0;
		}
		if(f[id]<mid){
			while(q.size() && q.back().fir>=r-mid) q.pop_back();
			q.push_back({r-mid,l+mid});
		}
	}
	if(!typ[x]){
		for(auto iter:inter[x]){
			int l,r,id; tie(l,r,id)=iter;
			if(r-l<mid && f[id]<mid) legal[x]=0;
		}
	}
	return ;
}
inline int check(int mid){
	rep(i,1,n) legal[i]=1;
	for(int i=1;i<=n;++i) solve(i,mid);
	for(int i=1;i<=n;++i) if(!typ[i]&&legal[i]) return i;
	return -1;
}
int main(){
	freopen("c.in","r",stdin); freopen("c.out","w",stdout);
	n=read(); 
	for(int i=1;i<=n;++i) typ[i]=read();
	for(int i=1;i<n;++i){
		int u=read(),v=read(),w=read();
		G[u].emplace_back(v,w);
		G[v].emplace_back(u,w);
	}
	ff[0]=1e9; cursum=n;
	findrt(1,0);
	build(rt);
	int l=0,r=1e9,val=0,node=0;
	while(l<=r){
		int mid=(l+r)>>1;
		int pos=check(mid);
		if(pos==-1) r=mid-1;
		else{
			l=mid+1;
			val=mid;
			node=pos;
		}
	}
	if(val==1e9) val=0;
	printf("%d %d\n",node,val);
	return 0;
}


标签:10,06,sub,int,auto,mid,ckmax,2022,id
来源: https://www.cnblogs.com/yspm/p/16367630.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有