20230928 比赛总结

反思

A

一开始感觉时间复杂度不够,后来还是冲了,发现很快

B

感觉自己卡常不行,要多练

C

巨大恶心题!写了我两个小时,心态差点崩了,还好调出来了
但出题人是 s b sb sb,卡常卡成暴力分了 ( 55 p t s ) (55pts) (55pts) T_T

题解

比赛链接

A

s b sb sb 题,枚举公约数然后二分即可,时间复杂度 O ( n l o g n l o g V ) O(nlognlogV) O(nlognlogV),因为是 g c d gcd gcd,所以 l o g V logV logV 远远跑不满

B

巨大恶心卡常题,不过只卡了 10 p t s 10pts 10pts
正解好像是倍增答案
但有人矩乘然后循环展开过了,感觉很神奇
u p d : upd : upd: 卡过了,用了循环展开,和 u n s i g n e d    l o n g    l o n g unsigned\;long\;long unsignedlonglong 减少取模次数,而且用循环展开,快了 3 3 3 倍,很神奇!!!感觉自己的机子比 n f l s nfls nfls 的评测机快

#include <bits/stdc++.h>
using namespace std;
const int K=135,P=1e9+7;
typedef unsigned long long ull;
struct Matrix{ int n,m,a[K<<1][K<<1];};
ull G[K<<1][K<<1];
Matrix operator *(const Matrix &A,const Matrix &B){
    Matrix C;C.n=A.n,C.m=B.m;
    int n=C.n,m=C.m;
    for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) G[i][j]=0;
    for(int i=1;i<=n;i++) for(int k=1;k<=m;k++) if(A.a[i][k]){
        int j=1;
        for(;j+7<=m;j+=8){
            G[i][j]+=1ll*A.a[i][k]*B.a[k][j];
            G[i][j+1]+=1ll*A.a[i][k]*B.a[k][j+1];
            G[i][j+2]+=1ll*A.a[i][k]*B.a[k][j+2];
            G[i][j+3]+=1ll*A.a[i][k]*B.a[k][j+3];
            G[i][j+4]+=1ll*A.a[i][k]*B.a[k][j+4];
            G[i][j+5]+=1ll*A.a[i][k]*B.a[k][j+5];
            G[i][j+6]+=1ll*A.a[i][k]*B.a[k][j+6];
            G[i][j+7]+=1ll*A.a[i][k]*B.a[k][j+7];
        }
        while(j<=C.m) G[i][j]+=1ll*A.a[i][k]*B.a[k][j],j++;
        if(k%16==0) for(int j=1;j<=m;j++) G[i][j]%=P;
    }
    for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) C.a[i][j]=G[i][j]%P;
    return C;
}
int n,k,a,b,f[2][K];
inline int read(){
	int FF=0,RR=1;
	char ch=getchar();
	for(;!isdigit(ch);ch=getchar()) if(ch=='-') RR=-1;
	for(;isdigit(ch);ch=getchar()) FF=(FF<<1)+(FF<<3)+ch-48;
	return FF*RR;
}
int qmi(int a,int b){
    int res=1;
    for(;b;b>>=1){
        if(b&1) res=1ll*res*a%P;
        a=1ll*a*a%P;
    }
    return res;
}
int main(){
    freopen("bird.in","r",stdin);
    freopen("bird.out","w",stdout);
	n=read(),k=read(),a=read(),b=read();
    Matrix A;A.n=A.m=k<<1;
    for(int i=1;i<=k;i++){
        A.a[i][i]=A.a[i+k][i+k]=1;
        if(i>1) A.a[i-1][i]=A.a[i+k-1][i+k]=1;
        if(i<k) A.a[i+1][i]=A.a[i+k+1][i+k]=1;
    }
    for(int i=a+1;i<b;i++){
        A.a[i][i+k]=1;
        if(i>1) A.a[i-1][i+k]=1;
        if(i<k) A.a[i+1][i+k]=1;
    }
    Matrix B;B.n=1,B.m=k<<1;B.a[1][k/2]=1;
    int T=n-2;
    for(;T;T>>=1){
        if(T&1) B=B*A;
        A=A*A;
    }
    for(int i=1;i<=k;i++) f[0][i]=B.a[1][i+k];
    for(int i=1;i<=k;i++) f[1][i]=(1ll*f[0][i]+f[0][i-1]+f[0][i+1])%P;
	printf("%d\n",1ll*f[1][k/2]*qmi(n-2,P-2)%P);
	fprintf(stderr,"%d ms\n",int(1e3*clock()/CLOCKS_PER_SEC));
	return 0;
}

C

看到路径,不难想到点分治
然后就用线段树维护即可, 不难想但很难写
还被卡常了,现在才发现我的点分治板子是有多慢(卡常 + 改了 w x q wxq wxq 的点分治板子就过了)
时间复杂度 O ( n l o g 2 n ) O(nlog^2n) O(nlog2n)

#include <bits/stdc++.h>
using namespace std;
const int N=100100,inf=2e9;
typedef pair<int,int> pii;
int n,m,ans=-inf,tot,mnms;
int L[N],R[N],idx;
int val1[N],val2[N];
bool TTT[N],cov[N],vis[N];
vector<int> G[N];
vector<pii> key[N],revkey[N];
inline int read(){
	int FF=0,RR=1;
	char ch=getchar();
	for(;!isdigit(ch);ch=getchar()) if(ch=='-') RR=-1;
	for(;isdigit(ch);ch=getchar()) FF=(FF<<1)+(FF<<3)+ch-48;
	return FF*RR;
}
struct SegmentTree{
	int seg[N*3],tag[N*3];
	void clear(int tot){ for(int i=1;i<=tot*3;i++) seg[i]=-inf,tag[i]=0;}
	void down(int x,int val){ seg[x]+=val,tag[x]+=val;}
	void pushdown(int x){
		down(x<<1,tag[x]),down(x<<1^1,tag[x]);
		tag[x]=0;
	}
	void modify(int l,int r,int x,int L,int R,int val,int type){
		if(L<=l&&r<=R){
            if(type) down(x,val);
            else seg[x]=val;
            return;
        }
		pushdown(x);
		int mid=(l+r)>>1;
		if(mid>=L) modify(l,mid,x<<1,L,R,val,type);
		if(mid<R) modify(mid+1,r,x<<1^1,L,R,val,type);
		seg[x]=max(seg[x<<1],seg[x<<1^1]);
	}
}sg;
int siz[N];
void get_size_wxq(int u,int fa){
    siz[u]=1;
	for(int v:G[u]) if(!vis[v]&&v!=fa) get_size_wxq(v,u),siz[u]+=siz[v];
}
int get_root_wxq(int u,int fa,int &rt){
	int siz=1,ms=0;
	for(int v:G[u]) if(!vis[v]&&v!=fa){
		int t=get_root_wxq(v,u,rt);
		siz+=t,ms=max(ms,t);
	}
	ms=max(ms,tot-siz);
	if(ms<mnms) mnms=ms,rt=u;
	return siz;
}
void init(int u,int fa){
	L[u]=++idx,cov[u]=1,val1[u]=val2[u]=0;
	for(int v:G[u]) if(v!=fa&&!vis[v]) init(v,u);
	R[u]=idx;
}
void clcov_wxq(int u,int fa){
	cov[u]=0;
	for(int v:G[u]) if(v!=fa&&!vis[v]) clcov_wxq(v,u);
}
void wxq12(int u,int fa){
	TTT[u]=1;
	for(pii ke:key[u]) if(TTT[ke.first]) val1[u]+=ke.second;
	for(pii ke:revkey[u]) if(TTT[ke.first]) val2[u]+=ke.second;
	for(int v:G[u]) if(v!=fa&&!vis[v]) val1[v]+=val1[u],val2[v]+=val2[u],wxq12(v,u); 
    TTT[u]=0;
}
void add_wxq(int u,int Lb,int Rb,int val){
	for(pii ke:key[u]){
		int x=ke.first,w=ke.second;
		if(!cov[x]) continue;
		if(L[x]>1&&Lb<=L[x]&&R[x]<=Rb) sg.modify(1,idx,1,L[x],R[x],w*val,1);
	}
}
void wxq(int u,int fa,int Lb,int Rb,int rt){
	add_wxq(u,Lb,Rb,1);
	if(Lb<=Rb) ans=max(ans,val1[u]+sg.seg[1]-val1[rt]);
    for(int v:G[u]) if(v!=fa&&!vis[v]) wxq(v,u,Lb,Rb,rt);
	add_wxq(u,Lb,Rb,-1);
}
void insert_wxq(int u,int fa){
	sg.modify(1,idx,1,L[u],L[u],val2[u],0);
	for(int v:G[u]) if(v!=fa&&!vis[v]) insert_wxq(v,u);
}
void wxq_solve(int rt){
	get_size_wxq(rt,-1),mnms=inf,tot=siz[rt];
	// get_root_wxq(rt,-1,rt);
    while(true){
        bool fl=0;
        for(auto v:G[rt])if(siz[v]<siz[rt]&&siz[v]*2>=tot){
            fl=1,rt=v;
            break;
        }
        if(!fl)break;
    }
	vis[rt]=1;
	idx=0,init(rt,-1);
	wxq12(rt,-1);
    ans=max(ans,val1[rt]);
	sg.clear(idx);sg.modify(1,idx,1,1,1,val2[rt],0);
	for(int v:G[rt]){
		if(vis[v]) continue;
		wxq(v,rt,1,L[v]-1,rt),insert_wxq(v,rt);
	}
	sg.clear(idx);
	for(int i=G[rt].size()-1;i>=0;i--){
		int v=G[rt][i];
		if(vis[v]) continue;
		wxq(v,rt,R[v]+1,idx,rt),insert_wxq(v,rt);
	}
    ans=max(ans,sg.seg[1]);
	clcov_wxq(rt,-1);
	for(int v:G[rt]) if(!vis[v]) wxq_solve(v); 
}
int main(){
    freopen("score.in","r",stdin);
    freopen("score.out","w",stdout);
	n=read(),m=read();
	for(int i=1;i<n;i++){
		int x=read(),y=read();
		G[x].emplace_back(y),G[y].emplace_back(x);
	}
	for(int i=1,x,y,w;i<=m;i++){
		x=read(),y=read(),w=read();
		key[y].emplace_back(make_pair(x,w));
		revkey[x].emplace_back(make_pair(y,w));
	}
	wxq_solve(1);
	printf("%d\n",ans);
	return 0;
}
// orz wxq

D

不会,是道动态 m s t mst mst 板子题
u p d : upd: upd: 现在会了,题解见 P3206城市建设 题解
贴上这题的代码(基本不用改

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=300100,M=600100,inf=2e9;
struct Lines{ int x,y,z,id;}e[30][M],f[M],tmp[M],t[M];
struct Updt{ int x,d;}upd[M];
int n,m,q,c[M],fa[N],rv[M],totE[30];
LL ans[M];
inline int read(){
	int FF=0,RR=1;
	char ch=getchar();
	for(;!isdigit(ch);ch=getchar()) if(ch=='-') RR=-1;
	for(;isdigit(ch);ch=getchar()) FF=(FF<<1)+(FF<<3)+ch-48;
	return FF*RR;
}
void _clear(int curE){ for(int i=1;i<=curE;i++) fa[f[i].x]=f[i].x,fa[f[i].y]=f[i].y;}
void _sort(int curE){ sort(f+1,f+curE+1,[](const Lines &i,const Lines &j){ return i.z<j.z;});}
int get_father(int x){ return x==fa[x]?x:fa[x]=get_father(fa[x]);}
void slv1(int &curE,LL &mst){
	_sort(curE),_clear(curE);
	int cnt=0;
	for(int i=1;i<=curE;i++){
		int fax=get_father(f[i].x),fay=get_father(f[i].y);
		if(fax!=fay) fa[fax]=fay,t[++cnt]=f[i];
	}
    _clear(curE);
    for(int i=1;i<=cnt;i++) if(t[i].z!=-inf) mst+=t[i].z,fa[get_father(t[i].x)]=get_father(t[i].y);
    int sz=0;
    for(int i=1;i<=curE;i++){
        int fax=get_father(f[i].x),fay=get_father(f[i].y);
        if(fax!=fay) f[i].x=fax,f[i].y=fay,tmp[++sz]=f[i];
    }
	for(int i=1;i<=sz;i++) f[i]=tmp[i],rv[f[i].id]=i;
    curE=sz;
}
void slv2(int &curE){
	_sort(curE),_clear(curE);
	int sz=0;
	for(int i=1;i<=curE;i++){
		int fax=get_father(f[i].x),fay=get_father(f[i].y);
		if(fax!=fay) fa[fax]=fay,tmp[++sz]=f[i];
		else if(f[i].z==inf) tmp[++sz]=f[i];
	}
	for(int i=1;i<=sz;i++) f[i]=tmp[i],rv[f[i].id]=i;
    curE=sz;
}
void solve(int l,int r,int depth,LL mst){
	int curE=totE[depth];
	if(l==r) c[upd[l].x]=upd[l].d;
	for(int i=1;i<=curE;i++){
		e[depth][i].z=c[e[depth][i].id];
		f[i]=e[depth][i],rv[f[i].id]=i;
	}
	if(l==r){
		ans[l]=mst;
		_sort(curE),_clear(curE);
		for(int i=1;i<=curE;i++){
			int fax=get_father(f[i].x),fay=get_father(f[i].y);
			if(fax!=fay) fa[fax]=fay,ans[l]+=f[i].z;
		}
		return;
	}
	for(int i=l;i<=r;i++) f[rv[upd[i].x]].z=-inf;
	slv1(curE,mst);
	for(int i=l;i<=r;i++) f[rv[upd[i].x]].z=inf;
	slv2(curE);
	for(int i=1;i<=curE;i++) e[depth+1][i]=f[i];
	totE[depth+1]=curE;
	int mid=(l+r)>>1;
	solve(l,mid,depth+1,mst),solve(mid+1,r,depth+1,mst);
}
int main(){
    freopen("mst.in","r",stdin);
    freopen("mst.out","w",stdout);
	n=read(),m=read();
	for(int i=1,x;i<=n;i++) x=read(),e[0][i]={0,i,x,i},c[i]=x;
	for(int i=1;i<=m;i++){
		int x=read(),y=read(),z=read();
		e[0][i+n]={x,y,z,i+n},c[i+n]=z;
	}
	int q=read();
	for(int i=1;i<=q;i++) upd[i].x=read(),upd[i].d=read();
	totE[0]=n+m,solve(1,q,0,0);
	for(int i=1;i<=q;i++) printf("%lld\n",ans[i]);
	fprintf(stderr,"%d ms\n",int(1e3*clock()/CLOCKS_PER_SEC));
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值