zoukankan      html  css  js  c++  java
  • 省选测试25

    A. two

    分析

    考虑当前要删红边,删蓝边类似

    从根节点 (1) 开始 (dfs) 遍历整棵蓝树

    定义 (dfn1[i],dfn2[i)] 分别为 (dfs) 中进入节点 (i) 子树的时刻和 (dfs) 中离开节点 (i) 子树的时刻

    对于红树中的第 (i) 条边 (x[i],y[i])

    定义 (u[i]=min(dfn1[x[i]],dfn1[y[i]]),v[i]=max(dfn1[x[i]],dfn1[y[i]]))

    接下来考虑删除蓝树中的一条边 ((p, q)),这里令 (p)(q) 的父亲

    那么 ((p,q)), 对应的红树中的坏边,即为满足 (u[i],v[i]) 中有且仅有一个数落在区间 ([dfn1[q],dfn2[q]])

    可以分成两种情况

    (1)(dfn1[q] leq u[i] leq dfn2[q],v[i]>dfn2[q])

    (2)、$dfn1[q] leq v[i] leq dfn2[q],u[i]<dfn1[q] $

    那么就可以开两颗线段树,线段树的每一个节点维护一个(vector)

    第一颗以 (u[i]) 作为下标,按照 (v[i]) 从小到大排序

    第二颗以 (v[i]) 作为下标,按照 (u[i]) 从大到小排序

    查询的时候直接在线段树的节点对应的 (vector) 上不断 (popback) 即可

    因为每一条边只会存到 (log)(vector) 里,删过一次就不会恢复

    所以复杂度是 (nlogn) ,常数较大

    代码

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<vector>
    #define rg register
    inline int read(){
        rg int x=0,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();
        }
        return x*fh;
    }
    const int maxn=2e5+5;
    int n;
    struct Graph{
    	int h[maxn],tot;
    	struct asd{
    		int to,nxt;
    	}b[maxn<<1];
    	void ad(rg int aa,rg int bb){
    		b[tot].to=bb;
    		b[tot].nxt=h[aa];
    		h[aa]=tot++;
    	}
    	int dfn1[maxn],dfn2[maxn],siz[maxn],dfnc,x[maxn],y[maxn],jud[maxn],valu[maxn],valv[maxn];
    	void dfs(rg int now,rg int lat){
    		siz[now]=1;
    		dfn1[now]=++dfnc;
    		for(rg int i=h[now];i!=-1;i=b[i].nxt){
    			rg int u=b[i].to;
    			if(u==lat) continue;
    			dfs(u,now);
    			siz[now]+=siz[u];
    		}
    	}
    	void build(){
    		tot=1;
    		memset(h,-1,sizeof(h));
    		rg int aa;
    		for(rg int i=2;i<=n;i++){
    			aa=read();
    			x[i-1]=i,y[i-1]=aa;
    			ad(aa,i),ad(i,aa);
    		}
    		dfs(1,0);
    		for(rg int i=1;i<=n;i++) dfn2[i]=dfn1[i]+siz[i]-1;
    	}
    }gra[2];
    int sta[maxn],tp,sta2[maxn],tp2;
    struct jie{
    	int val,id;
    	jie(){}
    	jie(rg int aa,rg int bb){
    		val=aa,id=bb;
    	}
    };
    bool cmp1(rg jie aa,rg jie bb){
    	return aa.val<bb.val;
    }
    bool cmp2(rg jie aa,rg jie bb){
    	return aa.val>bb.val;
    }
    struct Tree{
    	std::vector<jie> gup[maxn<<2],gdow[maxn<<2];
    	void ad(rg int da,rg int nl,rg int nr,rg int wz,rg int val,rg int id,rg int op){
    		if(op==0) gup[da].push_back(jie(val,id));
    		else gdow[da].push_back(jie(val,id));
    		if(nl==nr) return;
    		rg int mids=(nl+nr)>>1;
    		if(wz<=mids) ad(da<<1,nl,mids,wz,val,id,op);
    		else ad(da<<1|1,mids+1,nr,wz,val,id,op);
    	}
    	void dfs(rg int da,rg int nl,rg int nr){
    		std::sort(gup[da].begin(),gup[da].end(),cmp1);
    		std::sort(gdow[da].begin(),gdow[da].end(),cmp2);
    		if(nl==nr) return;
    		rg int mids=(nl+nr)>>1;
    		dfs(da<<1,nl,mids),dfs(da<<1|1,mids+1,nr);
    	}
    	void cx(rg int da,rg int nl,rg int nr,rg int l,rg int r,rg int val,rg int op,rg int col){
    		if(nl>=l && nr<=r){
    			if(op==0){
    				rg int tmp=gup[da].size();
    				while(tmp && gup[da][tmp-1].val>val){
    					if(!gra[col].jud[gup[da][tmp-1].id]) sta[++tp]=gup[da][tmp-1].id;
    					gra[col].jud[gup[da][tmp-1].id]=1;
    					tmp--,gup[da].pop_back();
    				}
    			} else {
    				rg int tmp=gdow[da].size();
    				while(tmp && gdow[da][tmp-1].val<val){
    					if(!gra[col].jud[gdow[da][tmp-1].id]) sta[++tp]=gdow[da][tmp-1].id;
    					gra[col].jud[gdow[da][tmp-1].id]=1;
    					tmp--,gdow[da].pop_back();
    				}
    			}
    			return;
    		}
    		rg int mids=(nl+nr)>>1;
    		if(l<=mids) cx(da<<1,nl,mids,l,r,val,op,col);
    		if(r>mids) cx(da<<1|1,mids+1,nr,l,r,val,op,col);
    	}
    }tre[2];
    int main(){
    	n=read();
    	gra[0].build(),gra[1].build();
    	sta[tp=1]=read();
    	for(rg int o=0;o<=1;o++){
    		for(rg int i=1;i<n;i++){
    			gra[o].valu[i]=std::min(gra[o].dfn1[gra[o^1].x[i]],gra[o].dfn1[gra[o^1].y[i]]);
    			gra[o].valv[i]=std::max(gra[o].dfn1[gra[o^1].x[i]],gra[o].dfn1[gra[o^1].y[i]]);
    		}
    	}
    	for(rg int o=0;o<=1;o++){
    		for(rg int i=1;i<n;i++){	
    			if(o==1 && i==sta[1]) continue;
    			tre[o].ad(1,1,n,gra[o].valu[i],gra[o].valv[i],i,0);
    			tre[o].ad(1,1,n,gra[o].valv[i],gra[o].valu[i],i,1);
    		}
    	}
    	tre[0].dfs(1,1,n),tre[1].dfs(1,1,n);
    	rg int aa,bb,now=0;
    	printf("Blue
    %d
    ",sta[1]);
    	gra[0].jud[sta[1]]=1;
    	while(1){
    		now^=1;
    		for(rg int i=1;i<=tp;i++) sta2[i]=sta[i];
    		tp2=tp,tp=0;
    		for(rg int i=1;i<=tp2;i++){
    			aa=gra[now^1].x[sta2[i]],bb=gra[now^1].y[sta2[i]];
    			if(gra[now^1].dfn1[aa]>gra[now^1].dfn1[bb]) std::swap(aa,bb);
    			tre[now^1].cx(1,1,n,gra[now^1].dfn1[bb],gra[now^1].dfn2[bb],gra[now^1].dfn2[bb],0,now);
    			tre[now^1].cx(1,1,n,gra[now^1].dfn1[bb],gra[now^1].dfn2[bb],gra[now^1].dfn1[bb],1,now);
    		}
    		if(!tp) break;
    		std::sort(sta+1,sta+1+tp);
    		if(now==1) printf("Red
    ");
    		else printf("Blue
    ");
    		for(rg int i=1;i<=tp;i++) printf("%d ",sta[i]);
    		printf("
    ");
    	}
    	return 0;
    }
    

    B. bracket

    分析

    对这棵树进行点分治,求出重心到每个点的前缀和 (s)

    对于两个点 (i, j) ,假设是从 (i) 开始走到 (j)

    如果它们的 (s) 互为相反数

    且它们的 (s) 都是重心到它们的路径上前缀和的最大/最小值

    那么就是一个合法的括号序列,划分段数就是最值出现的次数

    可以理解为合法括号左边的一段必须满足前缀非负,右边的一段必须满足前缀非正

    反过来之后就是前缀和的最大最小值

    对于重心进行一遍 (dfs) 就可以得到的划分段数以及前缀和

    对于前缀和互为相反数的括号序列

    按照正负分别存储到两个数组,以划分段数为下标进行卷积就能得到结果

    如果两个括号序列的划分段数都为 (0),那么下标就不减一,否则拼合后还会少一段,下标要减一

    需要注意的是重心的贡献只能算一次,所以 (dfs) 的时候记录两个 (sum)

    一个代表不选重心的,一个代表选重心的

    而且为了防止重复,需要强行规定选重心的只能是前缀,不选重心的只能是后缀

    还要注意的是在进行某个节点整体的更新时,有可能进入不到叶子节点中,此时如果不提前把最大值设为 (1),会出现有的 (vector) 没清空的情况

    代码

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<cstdlib>
    #include<algorithm>
    #include<ctime>
    #include<vector>
    #define rg register
    inline int read(){
    	rg int x=0,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();
    	}
    	return x*fh;
    }
    const int maxn=3e5+5,mod=998244353,G=3;
    int w[25][maxn],wz[maxn];
    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;
    }
    void ntt(rg int A[],rg int lim,rg int typ){
    	for(rg int i=0;i<lim;i++) if(i<wz[i]) std::swap(A[i],A[wz[i]]);
    	for(rg int len=1,t0=0;len<lim;len<<=1,t0++){
    		for(rg int j=0,now=len<<1;j<lim;j+=now){
    			for(rg int k=0;k<len;k++){
    				rg int x=A[j+k],y=mulmod(A[j+k+len],w[t0][k]);
    				A[j+k]=addmod(x,y),A[j+k+len]=delmod(x,y);
    			}
    		}
    	}
    	if(typ==-1){
    		rg int ny=ksm(lim,mod-2);
    		std::reverse(A+1,A+lim);
    		for(rg int i=0;i<lim;i++) A[i]=mulmod(A[i],ny);
    	}
    }
    void pre(rg int mmax){
    	for(rg int len=1,t0=0;len<mmax;len<<=1,t0++){
    		w[t0][0]=1,w[t0][1]=ksm(G,(mod-1)/(len<<1));
    		for(rg int j=1;j<len;j++) w[t0][j]=mulmod(w[t0][j-1],w[t0][1]);
    	}
    }
    int h[maxn],tot=1;
    long long ans[maxn];
    struct asd{
    	int to,nxt;
    }b[maxn];
    void ad(rg int aa,rg int bb){
    	b[tot].to=bb;
    	b[tot].nxt=h[aa];
    	h[aa]=tot++;
    }
    int a[maxn],n,m,rt,maxsiz[maxn],siz[maxn],totsiz;
    bool vis[maxn];
    void getroot(rg int now,rg int lat){
    	siz[now]=1,maxsiz[now]=0;
    	for(rg int i=h[now];i!=-1;i=b[i].nxt){
    		rg int u=b[i].to;
    		if(u==lat || vis[u]) continue;
    		getroot(u,now);
    		siz[now]+=siz[u];
    		maxsiz[now]=std::max(maxsiz[now],siz[u]);
    	}
    	maxsiz[now]=std::max(maxsiz[now],totsiz-siz[now]);
    	if(maxsiz[now]<maxsiz[rt]) rt=now;
    }
    void getsiz(rg int now,rg int lat){
    	siz[now]=1;
    	for(rg int i=h[now];i!=-1;i=b[i].nxt){
    		rg int u=b[i].to;
    		if(u==lat || vis[u]) continue;
    		getsiz(u,now);
    		siz[now]+=siz[u];
    	}
    }
    std::vector<int> wz1[maxn],wz2[maxn];
    int mx,mn,cnt1[maxn],cnt2[maxn],f[maxn];
    void dfs(rg int now,rg int lat,rg int summax,rg int summin,rg int mmax,rg int mmin,rg int cntmax,rg int cntmin){
    	summax+=a[now],summin+=a[now];
    	if(summax>mmax) mmax=summax,cntmax=0;
    	if(summax==mmax) cntmax++,wz1[mmax].push_back(cntmax);
    	if(summin<mmin) mmin=summin,cntmin=0;
    	if(summin==mmin) cntmin++,wz2[-mmin].push_back(cntmin);
    	mn=std::min(mn,mmin),mx=std::max(mx,mmax);
    	for(rg int i=h[now];i!=-1;i=b[i].nxt){
    		rg int u=b[i].to;
    		if(u==lat || vis[u]) continue;
    		dfs(u,now,summax,summin,mmax,mmin,cntmax,cntmin);
    	}
    }
    void js(rg int op){
    	for(rg int now=0;now<=mx && -now>=mn;now++){
    		rg int maxdep=0;
    		for(rg int i=0;i<wz1[now].size();i++){
    			rg int tmp=wz1[now][i];
    			maxdep=std::max(maxdep,tmp);
    			cnt1[tmp]++;
    		}
    		for(rg int i=0;i<wz2[now].size();i++){
    			rg int tmp=wz2[now][i];
    			maxdep=std::max(maxdep,tmp);
    			cnt2[tmp]++;
    		}
    		rg int lim=1,bit=0;
    		for(;lim<=maxdep+maxdep;lim<<=1) bit++;
    		for(rg int i=0;i<lim;i++) wz[i]=(wz[i>>1]>>1)|((i&1)<<(bit-1));
    		ntt(cnt1,lim,1),ntt(cnt2,lim,1);
    		for(rg int i=0;i<lim;i++) f[i]=mulmod(cnt1[i],cnt2[i]);
    		ntt(f,lim,-1);
    		if(now==0) for(rg int i=0;i<lim;i++) ans[i]+=f[i]*op;
    		else for(rg int i=1;i<=lim;i++) ans[i-1]+=f[i]*op;
    		for(rg int i=0;i<lim;i++) f[i]=cnt1[i]=cnt2[i]=0;
    	}
    	for(rg int i=0;i<=mx;i++) wz1[i].clear();
    	for(rg int i=0;-i>=mn;i++) wz2[i].clear();
    }
    void solve(rg int now){
    	vis[now]=1;
    	getsiz(now,0);
    	for(rg int i=h[now];i!=-1;i=b[i].nxt){
    		rg int u=b[i].to;
    		if(vis[u]) continue;
    		mx=mn=0;
    		dfs(u,0,a[now],0,a[now]>0,0,a[now]>0,0);
    		js(-1);
    	}
    	if(a[now]>0) wz1[1].push_back(1);
    	mx=a[now]>0,mn=0;
    	cnt2[0]++;
    	for(rg int i=h[now];i!=-1;i=b[i].nxt){
    		rg int u=b[i].to;
    		if(vis[u]) continue;
    		dfs(u,0,a[now],0,a[now]>0,0,a[now]>0,0);
    	}
    	js(1);
    	for(rg int i=h[now];i!=-1;i=b[i].nxt){
    		rg int u=b[i].to;
    		if(vis[u]) continue;
    		rt=0,totsiz=siz[u];
    		getroot(u,0);
    		solve(rt);
    	}
    }
    int main(){
    	memset(h,-1,sizeof(h));
    	n=read();
    	rg int lim=1;
    	for(;lim<=n+n;lim<<=1);
    	pre(lim);
    	rg int aa,bb;
    	for(rg int i=1;i<n;i++){
    		aa=read(),bb=read();
    		ad(aa,bb),ad(bb,aa);
    	}
    	rg char ch;
    	for(rg int i=1;i<=n;i++){
    		scanf(" %c",&ch);
    		if(ch=='(') a[i]=1;
    		else a[i]=-1;
    	}
    	maxsiz[0]=0x3f3f3f3f,totsiz=n,rt=0;
    	getroot(1,0);
    	solve(rt);
    	m=read();
    	for(rg int i=1;i<=m;i++){
    		aa=read();
    		printf("%lld
    ",ans[aa]);
    	}
    	return 0;
    }
    

    C. sum

    分析

    结论题

    (1)、最优集合里每个数最多只有两个不同的质因子

    (2)、若一个数含有两个不同质因子,则一定满足一个 (< sqrt{n}),一个 (>sqrt{n})

    所以可以建出二分图跑一个最大费用可行流

    答案就是一开始的答案加上跑出的费用

    不能跑最大费用最大流,因为有可能为了增广流量而去走费用为负的边

    区别就是前者在最长路小于 (0) 的时候直接退出就行了

    代码

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<queue>
    #include<cmath>
    #define rg register
    inline int read(){
    	rg int x=0,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();
    	}
    	return x*fh;
    }
    const int maxn=1e6+5;
    int n,ans,pri[maxn],mmax[maxn],s,t,cnt;
    bool not_pri[maxn];
    void xxs(){
    	not_pri[0]=not_pri[1]=1;
    	for(rg int i=2;i<=n;i++){
    		if(!not_pri[i]) pri[++pri[0]]=i;
    		for(rg int j=1;j<=pri[0] && i*pri[j]<=n;j++){
    			not_pri[i*pri[j]]=1;
    			if(i%pri[j]==0) break;
    		}
    	}
    }
    std::queue<int> q;
    int dis[maxn],incf[maxn],pre[maxn],h[maxn],tot=2;
    bool inq[maxn];
    struct asd{
    	int to,nxt,val,cost;
    }b[maxn<<1];
    void ad(rg int aa,rg int bb,rg int cc,rg int dd){
    	b[tot].to=bb;
    	b[tot].val=cc;
    	b[tot].cost=dd;
    	b[tot].nxt=h[aa];
    	h[aa]=tot++;
    }
    bool spfa(){
    	for(rg int i=1;i<=cnt;i++) dis[i]=-0x3f3f3f3f,incf[i]=0;
    	dis[s]=0,inq[s]=1,q.push(s),incf[s]=0x3f3f3f3f;
    	while(!q.empty()){
    		rg int now=q.front();
    		q.pop();
    		inq[now]=0;
    		for(rg int i=h[now];i!=-1;i=b[i].nxt){
    			rg int u=b[i].to;
    			if(b[i].val && dis[u]<dis[now]+b[i].cost){
    				dis[u]=dis[now]+b[i].cost;
    				pre[u]=i;
    				incf[u]=std::min(incf[now],b[i].val);
    				if(!inq[u]){
    					inq[u]=1;
    					q.push(u);
    				}
    			}
    		}
    	}
    	return dis[t]!=-0x3f3f3f3f;
    }
    int ans2=0;
    void updat(){
    	if(dis[t]<0){
    		printf("%d
    ",ans+1);
    		std::exit(0);
    	}
    	ans+=dis[t]*incf[t];
    	rg int i,now=t;
    	while(now){
    		i=pre[now];
    		b[i].val-=incf[t];
    		b[i^1].val+=incf[t];
    		now=b[i^1].to;
    	}
    }
    int prinum,tax[maxn],rk[maxn];
    void solve(rg int val){
    	prinum=0;
    	rg int tmp=val;
    	for(rg int i=2;i*i<=val;i++){
    		if(val%i==0){
    			tax[++prinum]=i;
    			while(val%i==0) val/=i;
    		}
    	}
    	if(val>1) tax[++prinum]=val;
    	if(prinum!=2) return;
    	if(tax[1]>tax[2]) std::swap(tax[1],tax[2]);
    	if(1LL*tax[1]*tax[1]>=n || 1LL*tax[2]*tax[2]<=n) return;
    	rg int tmpans=0;
    	for(rg int i=1;i<=prinum;i++){
    		if(tmp*tax[i]<=n) return;
    		tmpans+=mmax[tax[i]];
    	}
    	if(tmpans<tmp){
    		ad(rk[tax[1]],rk[tax[2]],1,tmp-tmpans),ad(rk[tax[2]],rk[tax[1]],0,tmpans-tmp);
    	}
    }
    int main(){
    	memset(h,-1,sizeof(h));
    	n=read();
    	xxs();
    	for(rg int i=1;i<=pri[0];i++){
    		rg int now=pri[i];
    		while(1LL*now*pri[i]<=n) now*=pri[i];
    		mmax[pri[i]]=now;
    		ans+=now;
    	}
    	s=1,t=2,cnt=2;
    	for(rg int i=1;i<=pri[0];i++){
    		if(1LL*pri[i]*pri[i]<n){
    			if(!rk[pri[i]]) rk[pri[i]]=++cnt;
    			ad(s,rk[pri[i]],1,0),ad(rk[pri[i]],s,0,0);
    		} else if(1LL*pri[i]*pri[i]>n){
    			if(!rk[pri[i]]) rk[pri[i]]=++cnt;
    			ad(rk[pri[i]],t,1,0),ad(t,rk[pri[i]],0,0);
    		}
    	}
    	for(rg int i=2;i<=n;i++) solve(i);
    	while(spfa()) updat();
    	printf("%d
    ",ans+1);
    	return 0;
    }
    
  • 相关阅读:
    OSX安装nginx和rtmp模块(rtmp直播服务器搭建)
    用runtime来重写Coder和deCode方法 归档解档的时候使用
    Homebrew安装卸载
    Cannot create a new pixel buffer adaptor with an asset writer input that has already started writing'
    OSX下面用ffmpeg抓取桌面以及摄像头推流进行直播
    让nginx支持HLS
    iOS 字典转json字符串
    iOS 七牛多张图片上传
    iOS9UICollectionView自定义布局modifying attributes returned by UICollectionViewFlowLayout without copying them
    Xcode6 iOS7模拟器和Xcode7 iOS8模拟器离线下载
  • 原文地址:https://www.cnblogs.com/liuchanglc/p/14426875.html
Copyright © 2011-2022 走看看