省选测试42

省选测试42

总结

这次是真的掉没了,\(T1\) 加了一个剪枝直接把 \(60\) 分减没了,以后遇到这种情况还是要稳一点,不要把暴力留着,尤其是这种数据不是很好构造的题。

A. 小B的棋盘

分析

将所有的点按照横坐标从小到大排序,如果横坐标相同按照纵坐标从小到大排序。

如果我们确定了一个对称中心,那么判断方法就是维护两个指针,一个从前向后扫,一个从后向前扫,求出有多少对点匹配,也就可以求出我们需要加入多少点。

因为我们最多只能加入 \(k\) 个点,所以失配的次数不能超过 \(k\) 次。

因此就可以把最开始的 \(k+1\) 个点和最后的 \(k+1\) 个点选择一对强制匹配,最终的合法方案一定是在这些方案中的。

判断的时候可以 \(nlogn\) 判断,总的复杂度就是 \(k^2nlogn\)

代码

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cmath>
#include<set>
#define rg register
template<typename T>void read(rg T& x){
	x=0;rg int fh=1;
	rg char ch=getchar();
	while(ch<'0' || ch>'9'){
		if(ch=='-') fh=-1;
		ch=getchar();
	}
	while(ch>='0' && ch<='9'){
		x=(x<<1)+(x<<3)+(ch^48);
		ch=getchar();
	}
	x*=fh;
}
const int maxn=1e5+5;
int n,k,x[maxn],y[maxn],ans,tp;
struct Node{
	long long x,y;
	Node(){}
	Node(rg long long aa,rg long long bb){
		x=aa,y=bb;
	}
	friend bool operator <(const Node& A,const Node& B){
		if(A.x==B.x) return A.y<B.y;
		return A.x<B.x;
	}
}sta[maxn];
std::set<Node> s,mp,orz;
#define sit std::set<Node>::iterator
bool jud(rg long long nx,rg long long ny){
	rg sit it=mp.find(Node(nx,ny));
	if(it!=mp.end() && it->x==nx && it->y==ny) return 0;
	rg int cnt=0;
	rg long long mx,my;
	for(rg int i=1;i<=n;i++){
		mx=2LL*nx-x[i];
		my=2LL*ny-y[i];
		it=s.find(Node(mx,my));
		if(it==s.end() || it->x!=mx || it->y!=my) cnt++;
		if(cnt>k) return 0;
	}
	mp.insert(Node(nx,ny));
	return 1;
}
int main(){
	read(n),read(k);
	for(rg int i=1;i<=n;i++){
		read(x[i]),read(y[i]);
		x[i]*=2,y[i]*=2;
		s.insert(Node(x[i],y[i]));
		sta[++tp]=Node(x[i],y[i]);
	}
	if(k>=n){
		printf("-1\n");
		return 0;
	}
	std::sort(sta+1,sta+tp+1);
	for(rg int i=1;i<=k+1;i++){
		for(rg int j=tp-k;j<=tp;j++){
			ans+=jud(1LL*(sta[i].x+sta[j].x)/2LL,1LL*(sta[i].y+sta[j].y)/2LL);
		}
	}
	printf("%d\n",ans);
	return 0;
}

B. 小B的夏令营

分析

\(f[t][l][r]\) 为当前考虑到了第 \(t\) 行,前 \(i\) 行都联通并且剩下的区间是 \([l,r]\) 的概率。

暴力的转移是 \(n^5\) 的,拿前缀和优化一下就是 \(n^3\) 的。

发现其实并不需要维护具体的 \(f\) 值,只需要维护前缀和的值就行了,拆一下式子就可以做到 \(n^2\)

代码

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cmath>
#include<queue>
#define rg register
template<typename T>void read(rg T& x){
	x=0;rg int fh=1;
	rg char ch=getchar();
	while(ch<'0' || ch>'9'){
		if(ch=='-') fh=-1;
		ch=getchar();
	}
	while(ch>='0' && ch<='9'){
		x=(x<<1)+(x<<3)+(ch^48);
		ch=getchar();
	}
	x*=fh;
}
const int maxn=1505,mod=1e9+7,maxm=1e5+5;
inline int addmod(rg int now1,rg int now2){
	return now1+=now2,now1>=mod?now1-mod:now1;
}
inline int delmod(rg int now1,rg int now2){
	return now1-=now2,now1<0?now1+mod:now1;
}
inline int mulmod(rg long long now1,rg int now2){
	return now1*=now2,now1>=mod?now1%mod:now1;
}
inline int ksm(rg int ds,rg int zs){
	rg int nans=1;
	while(zs){
		if(zs&1) nans=mulmod(nans,ds);
		ds=mulmod(ds,ds);
		zs>>=1;
	}
	return nans;
}
int n,m,a,b,k,ans,p[maxn],ny[maxm],jc[maxm],jcc[maxm],gl;
int suml[2][maxn],sumr[2][maxn],suml2[maxn],sumr2[maxn],suml3[maxn],sumr3[maxn],sumpl[maxn],sumpr[maxn];
int getp(rg int l,rg int r){
	return mulmod(p[l-1],p[m-r]);
}
int getC(rg int nn,rg int mm){
	return mulmod(jc[nn],mulmod(jcc[nn-mm],jcc[mm]));
}
int main(){
	read(n),read(m),read(a),read(b),read(k);
	gl=mulmod(a,ksm(b,mod-2));
	ny[1]=1;
	for(rg int i=2;i<maxm;i++) ny[i]=mulmod(mod-mod/i,ny[mod%i]);
	jc[0]=jcc[0]=1;
	for(rg int i=1;i<maxm;i++) jc[i]=mulmod(jc[i-1],i),jcc[i]=mulmod(jcc[i-1],ny[i]);
	for(rg int i=0;i<=m && i<=k;i++) p[i]=mulmod(getC(k,i),mulmod(ksm(gl,i),ksm(delmod(1,gl),k-i)));
	for(rg int i=1;i<=m;i++){
		for(rg int j=1;j<=i;j++){
			sumpr[i]=addmod(sumpr[i],getp(j,i));
		}
	}
	for(rg int i=1;i<=m;i++){
		for(rg int j=i;j<=m;j++){
			sumpl[i]=addmod(sumpl[i],getp(i,j));
		}
	}
	rg int now=0;
	sumr[now][m]=1,suml[now][1]=1;
	for(rg int o=1;o<=n;o++){
		memset(suml2,0,sizeof(suml2));
		memset(sumr2,0,sizeof(sumr2));
		memset(suml3,0,sizeof(suml3));
		memset(sumr3,0,sizeof(sumr3));
		for(rg int i=1;i<=m;i++) sumr2[i]=addmod(sumr2[i-1],sumr[now][i]);
		for(rg int i=m;i>=1;i--) suml2[i]=addmod(suml2[i+1],suml[now][i]);
		for(rg int i=1;i<=m;i++) sumr3[i]=addmod(sumr3[i-1],mulmod(p[i-1],sumr2[i-1]));
		for(rg int i=m;i>=1;i--) suml3[i]=addmod(suml3[i+1],mulmod(p[m-i],suml2[i+1]));
		now^=1;
		memset(suml[now],0,sizeof(suml[now]));
		memset(sumr[now],0,sizeof(sumr[now]));
		for(rg int i=1;i<=m;i++){
			sumr[now][i]=addmod(sumr[now][i],mulmod(sumr2[m],sumpr[i]));
			sumr[now][i]=delmod(sumr[now][i],mulmod(suml2[i+1],sumpr[i]));
			sumr[now][i]=delmod(sumr[now][i],mulmod(p[m-i],sumr3[i]));
		}
		for(rg int i=1;i<=m;i++){
			suml[now][i]=addmod(suml[now][i],mulmod(sumr2[m],sumpl[i]));
			suml[now][i]=delmod(suml[now][i],mulmod(sumr2[i-1],sumpl[i]));
			suml[now][i]=delmod(suml[now][i],mulmod(p[i-1],suml3[i]));
		}
	}
	for(rg int i=1;i<=m;i++) ans=addmod(ans,sumr[now][i]);
	printf("%d\n",ans);
	return 0;
}

C. 小B的图

分析

首先,不管什么 \(x\),选出的边一定要么是 \(A\) 的最小生成树边,要么是 \(B\) 的最小生成树边。

我们搞出 \(A\) 的最小生成树,把 \(B\) 的边从小到大依次加入替代 \(A\) 边。

每条边替换时我们能知道这条边在 $ \ge x_0$ 时才会被替换。

排个序然后每次询问二分就行。

代码

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cmath>
#define rg register
template<typename T>void read(rg T& x){
	x=0;rg int fh=1;
	rg char ch=getchar();
	while(ch<'0' || ch>'9'){
		if(ch=='-') fh=-1;
		ch=getchar();
	}
	while(ch>='0' && ch<='9'){
		x=(x<<1)+(x<<3)+(ch^48);
		ch=getchar();
	}
	x*=fh;
}
const int maxn=1e6+5;
struct LCT{
	int rev[maxn],wz[maxn],val[maxn],mmax[maxn],ch[maxn][2],fa[maxn],sta[maxn],tp;
	void push_up(rg int da){
		rg int lc=ch[da][0],rc=ch[da][1];
		mmax[da]=std::max(val[da],std::max(mmax[lc],mmax[rc]));
		if(mmax[da]==val[da]) wz[da]=da;
		else if(mmax[da]==mmax[lc]) wz[da]=wz[lc];
		else wz[da]=wz[rc];
	}
	void push_down(rg int da){
		if(!rev[da]) return;
		rg int lc=ch[da][0],rc=ch[da][1];
		rev[da]^=1,rev[lc]^=1,rev[rc]^=1;
		std::swap(ch[da][0],ch[da][1]);
	}
	bool isroot(rg int da){
		return (ch[fa[da]][0]!=da)&&(ch[fa[da]][1]!=da);
	}
	void xuanzh(rg int x){
		rg int y=fa[x];
		rg int z=fa[y];
		rg int k=(ch[y][1]==x);
		if(!isroot(y)) ch[z][ch[z][1]==y]=x;
		fa[x]=z;
		ch[y][k]=ch[x][k^1];
		fa[ch[x][k^1]]=y;
		ch[x][k^1]=y;
		fa[y]=x;
		push_up(y);
		push_up(x);
	}
	void splay(rg int x){
		sta[tp=1]=x;
		for(rg int i=x;!isroot(i);i=fa[i]) sta[++tp]=fa[i];
		for(rg int i=tp;i>=1;i--) push_down(sta[i]);
		while(!isroot(x)){
			rg int y=fa[x];
			rg int z=fa[y];
			if(!isroot(y)){
				(ch[z][1]==y)^(ch[y][1]==x)?xuanzh(x):xuanzh(y);
			}
			xuanzh(x);
		}
	}
	void access(rg int x){
		for(rg int y=0;x;y=x,x=fa[x]){
			splay(x);
			ch[x][1]=y;
			push_up(x);
		}
	}
	void makeroot(rg int x){
		access(x);
		splay(x);
		rev[x]^=1;
		push_down(x);
	}
	void split(rg int x,rg int y){
		makeroot(x);
		access(y);
		splay(y);
	}
	void link(rg int x,rg int y){
		makeroot(x);
		fa[x]=y;
	}
	void cut(rg int x,rg int y){
		split(x,y);
		ch[y][0]=fa[x]=0;
		push_up(y);
	}
}lct;
int n,a,b,q,fa[maxn],idx[maxn],idy[maxn],idw[maxn],tp,wz[maxn];
struct jie{
	int zb,yb,val;
	jie(){}
	jie(rg int aa,rg int bb,rg int cc){
		zb=aa,yb=bb,val=cc;
	}
}c[maxn];
bool cmp(rg jie aa,rg jie bb){
	return aa.val<bb.val;
}
void init(){
	for(rg int i=1;i<=n;i++) fa[i]=i;
}
int zhao(rg int xx){
	if(xx==fa[xx]) return xx;
	return fa[xx]=zhao(fa[xx]);
}
long long ans[maxn];
struct asd{
	int val,tim;
	asd(){}
	asd(rg int aa,rg int bb){
		val=aa,tim=bb;
	}
}sta[maxn];
bool cmp2(rg asd aa,rg asd bb){
	return aa.tim<bb.tim;
}
int main(){
	read(n),read(a),read(b),read(q);
	for(rg int i=0;i<=n;i++) lct.val[i]=lct.mmax[i]=-0x3f3f3f3f;
	rg int aa,bb,cc;
	for(rg int i=1;i<=a;i++){
		read(aa),read(bb),read(cc);
		c[i]=jie(aa,bb,cc);
	}
	std::sort(c+1,c+a+1,cmp);
	init();
	for(rg int i=1;i<=a;i++){
		aa=zhao(c[i].zb),bb=zhao(c[i].yb);
		if(aa==bb) continue;
		fa[aa]=bb;
		lct.val[i+n]=lct.mmax[i+n]=c[i].val;
		idx[i+n]=c[i].zb,idy[i+n]=c[i].yb,idw[i+n]=c[i].val;
		lct.link(c[i].zb,i+n),lct.link(c[i].yb,i+n);
		ans[0]+=c[i].val;
	}
	for(rg int i=1;i<=b;i++){
		read(aa),read(bb),read(cc);
		c[i]=jie(aa,bb,cc);
	}
	std::sort(c+1,c+b+1,cmp);
	init();
	for(rg int i=1;i<=b;i++){
		aa=zhao(c[i].zb),bb=zhao(c[i].yb);
		if(aa==bb) continue;
		fa[aa]=bb;
		lct.split(c[i].zb,c[i].yb);
		cc=lct.wz[c[i].yb];
		lct.cut(idx[cc],cc),lct.cut(idy[cc],cc);
		lct.val[n+a+i]=lct.mmax[n+a+i]=-0x3f3f3f3f;
		lct.link(c[i].zb,n+a+i),lct.link(c[i].yb,n+a+i);
		sta[++tp]=asd(c[i].val-idw[cc],(int)std::ceil(1.0*(c[i].val-idw[cc])/2.0));
	}
	std::sort(sta+1,sta+tp+1,cmp2);
	for(rg int i=1;i<=tp;i++) ans[i]=ans[i-1]+sta[i].val;
	for(rg int i=1;i<=tp;i++) wz[i]=sta[i].tim;
	for(rg int i=1;i<=q;i++){
		read(aa);
		if(aa>=sta[tp].tim){
			printf("%lld\n",ans[tp]-1LL*(n-1)*aa);
		} else {
			bb=std::upper_bound(wz+1,wz+tp+1,aa)-wz;
			printf("%lld\n",ans[bb-1]+1LL*(n-1-(bb-1)-(bb-1))*aa);
		}
	}
	return 0;
}
posted @ 2021-03-25 19:43  liuchanglc  阅读(421)  评论(0编辑  收藏  举报