zoukankan      html  css  js  c++  java
  • CF869D The Overdosing Ubiquity 解题报告

    CF869D The Overdosing Ubiquity 解题报告:

    题意

    给定一个 \(n\) 个结点的完全二叉树,\(k\) 号点的父亲为 \(\lfloor\frac{k}{2}\rfloor\),新加 \(m\) 条边,求本质不同简单路径数量。

    \(1\leqslant n\leqslant 10^9,0\leqslant m\leqslant 4\)

    分析

    给一个常数大,码量大但好想的做法。

    首先不经过新加边的路径数量就是 \(O(n^2)\),然后考虑强制经过新加边的方案数。

    由于 \(m\) 很小,我们可以枚举选哪些边,枚举走边的顺序,枚举边的方向(也就是无向边变成有向边),然后考虑按照顺序依次经过钦定的边的路径数量。

    我们令 \((x_i,y_i)\) 为选择的第 \(i\) 条新加边(一共 \(k\) 条),取出两条路径 \(A\)\(B\)

    \(A\):从 \(y_1\) 沿着树上的边走到 \(x_2\),然后走 \((x_2,y_2)\),再从 \(y_2\) 沿着树上的边走到 \(x_3\)……
    \(B\)\(x_1\) 沿着树上的边走到 \(y_k\) 的路径。

    \(A\)\(B\) 有交,那么可以发现经过这些钦定边的路径的起点一定是 \(x\) 不经过 \(A\) 内点沿着树上的边能到达的点,同理终点一定是 \(y\) 不经过 \(B\) 内点沿着树上的边能到达的点。

    这个东西可以直接在树上搜一遍得到,也可以发现这个连通块一定是一个子树去掉若干子树的结果,大子树和去掉的子树都可以枚举 \(A\) 上的点计算出来,具体可以看代码。(\(\text{dfs}\) 部分)

    \(A\)\(B\) 没有交,那么可以发现我们几乎可以在 \(A\)\(B\) 到达的点中任选两个点作为起点和终点,但是这两个点 \(s,t\) 要满足 \((x_1,s)\)\((y_k,t)\) 无交
    ,我们枚举 \(B\) 上所有点,令枚举的点为 \(s\) 的祖先,那么 \(t\) 一定在 \(B\) 更后面的点的子树中,于是前缀和一下就做完了。

    然后你就写出了大分讨代码,接下来就只需要足够的耐心调试了!

    时间复杂度 \(O((m\log n)^3m!4^m)\),非常松,随便过。

    代码

    #include<stdio.h>
    #include<algorithm>
    #include<string.h>
    #include<map>
    using namespace std;
    const int maxn=1000005,mod=1000000007;
    int n,m,ans;
    int x[maxn],y[maxn],t[maxn],p[maxn],q[maxn],aa[maxn],bb[maxn],cc[maxn],dd[maxn],no[maxn];
    map<int,int>vis; 
    int getsize(int x){
    //	printf("getsize(%d)=",x);
    	int r=x,dep=1;
    	while((r<<1|1)<=n)
    		r=(r<<1|1),dep++;
    	int out=(r<<1|1);
    //	printf("%d\n",((1<<dep)-1)+max((1<<dep)-(out-n),0)); 
    	return ((1<<dep)-1)+max((1<<dep)-(out-n),0);
    }
    int isfa(int x,int y){
    	while(y){
    		if(x==y)
    			return 1;
    		y>>=1;
    	}
    	return 0;
    }
    void dfs(int x,int ban1,int ban2,int &c){
    	int nos=0;
    	for(map<int,int>::iterator it=vis.begin();it!=vis.end();it++)
    		if(it->second&&it->first!=x)
    			no[++nos]=it->first;
    	if(ban1&&vis[ban1]==0&&ban1!=x)
    		no[++nos]=ban1;
    	if(ban2&&vis[ban2]==0&&ban2!=x)
    		no[++nos]=ban2;
    	sort(no+1,no+1+nos);
    //	for(int i=1;i<=nos;i++)
    //		printf("%d%c",no[i],i==nos? '\n':' ');
    	int fa=0;
    	for(int i=1;i<=nos;i++)
    		if(no[i]&&no[i]<x&&isfa(no[i],x))
    			fa=max(fa,no[i]);
    	int y=x,lst=0;
    	while(y!=fa)
    		lst=(y&1),y>>=1;
    	fa=(fa<<1)|lst,c=getsize(fa);
    	for(int i=1;i<=nos;i++)
    		if(no[i]>fa&&isfa(fa,no[i]))
    			for(int j=i+1;j<=nos;j++)
    				if(no[j]&&no[j]>fa&&isfa(no[i],no[j]))
    					no[j]=0;
    	for(int i=1;i<=nos;i++)
    		if(no[i]&&fa<no[i]&&isfa(fa,no[i])){
    //			printf("i=%d no[i]=%d %d\n",i,no[i],getsize(no[i]));
    			c-=getsize(no[i]);
    		}
    //	printf("y=%d fa=%d\n",y,fa);
    //	printf("(dfs %d %d %d)=%d(fa=%d)\n",x,ban1,ban2,c,fa);
    	/*if(x==ban||x>n||x<1)
    		return ;
    	vis[x]=1,c++;
    	if(vis[x>>1]==0)
    		dfs(x>>1,ban,c);
    	if(vis[x<<1]==0)
    		dfs(x<<1,ban,c);
    	if(vis[x<<1|1]==0)
    		dfs(x<<1|1,ban,c); */
    }
    int main(){
    	scanf("%d%d",&n,&m),ans=1ll*n*n%mod;
    	if(m==0){
    		printf("%d\n",ans);
    		return 0;
    	}
    	for(int i=1;i<=m;i++)
    		scanf("%d%d",&x[i],&y[i]);
    	for(int i=1;i<(1<<m);i++){
    		int tot=0;
    		for(int j=1;j<=m;j++)
    			if((i>>(j-1))&1)
    				t[++tot]=j,p[tot]=tot;
    		do{
    			for(int j=1;j<=tot;j++)
    				q[j]=t[p[j]];
    			for(int j=0;j<(1<<tot);j++){
    //				printf("i=%d j=%d ans=%d\n",i,j,ans);
    				vis.clear();
    				for(int k=1;k<=tot;k++)
    					vis[x[q[k]]]=vis[y[q[k]]]=1;
    				for(int k=1;k<=tot;k++) 
    					if((j>>(k-1))&1)
    						swap(x[q[k]],y[q[k]]);
    				int flg=0;
    				for(int k=1;k<=tot;k++)
    					for(int r=k+1;r<=tot;r++)
    						if(x[q[k]]==x[q[r]]||y[q[k]]==y[q[r]]||x[q[k]]==y[q[r]]||(y[q[k]]==x[q[r]]&&r!=k+1))
    							flg=1;
    				for(int k=1;k<tot;k++){
    					int X=y[q[k]],Y=x[q[k+1]],a=__builtin_clz(X),b=__builtin_clz(Y),s=X,t=Y;
    					while(a<b){
    						s>>=1,a++;
    						if(s!=t)
    							flg|=vis[s],vis[s]=1;
    					}
    					while(b<a){
    						t>>=1,b++;
    						if(s!=t) 
    							flg|=vis[t],vis[t]=1;
    					}
    					while(s!=t){
    						s>>=1,a++,flg|=vis[s],vis[s]=1;
    						t>>=1,b++;
    						if(s!=t)
    							flg|=vis[t],vis[t]=1;
    					}
    				}
    //				for(int k=1;k<=tot;k++)
    //					printf("xx=%d yy=%d\n",x[k],y[k]);
    				if(flg==0){
    					int X=x[q[1]],Y=y[q[tot]],a=__builtin_clz(X),b=__builtin_clz(Y),s=X,t=Y,f=0,as=0,bs=0,cs=0;
    					while(a<b){
    						s>>=1,a++;
    						if(s!=t)
    							f|=vis[s],aa[++as]=s;
    					} 
    					while(b<a){
    						t>>=1,b++;
    						if(s!=t)
    							f|=vis[t],bb[++bs]=t;
    					}
    					while(s!=t){
    						s>>=1,a++,f|=vis[s],aa[++as]=s;
    						t>>=1,b++;
    						if(s!=t) 
    							f|=vis[t],bb[++bs]=t;
    					}
    					if(f){
    //						puts("case1");
    						int c0=0,c1=0;
    						dfs(X,0,0,c0),dfs(Y,0,0,c1);
    						ans=(ans+1ll*c0*c1)%mod;
    					}
    					else{
    //						puts("case2");
    						for(int k=1;k<=as;k++)
    							cc[++cs]=aa[k];
    						for(int k=bs;k>=1;k--)
    							cc[++cs]=bb[k];
    //						printf("X=%d Y=%d\n",X,Y);
    						cc[0]=X,cc[cs+1]=Y;
    /*						puts("CC");
    						for(int k=0;k<=cs+1;k++)
    							printf("%d%c",cc[k],k==cs+1? '\n':' ');*/
    						int all=0;
    //						puts("A");
    						dd[0]=0,dfs(X,0,cc[1],dd[0]),all+=dd[0];
    						for(int k=1;k<=cs;k++)
    							dd[k]=0,dfs(cc[k],cc[k-1],cc[k+1],dd[k]),all+=dd[k];
    //						puts("B");
    						dd[cs+1]=0,dfs(Y,0,cc[cs],dd[cs+1]),all+=dd[cs+1];
    /*						for(int k=0;k<=cs+1;k++)
    							printf("k=%d dd[k]=%d\n",k,dd[k]);*/
    						for(int k=0;k<=cs;k++)
    							all-=dd[k],ans=(ans+1ll*dd[k]*all)%mod;
    					}
    				}
    //				printf("i=%d j=%d ans=%d\n",i,j,ans);
    				for(int k=1;k<=tot;k++)
    					if((j>>(k-1))&1)
    						swap(x[q[k]],y[q[k]]);
    			}
    		}while(next_permutation(p+1,p+1+tot));
    //		printf("i=%d ans=%d\n",i,ans);
    	}
    	printf("%d\n",ans);
    	return 0;
    }
    
  • 相关阅读:
    记录五年社畜萌新尝试将静态网站在docker上使用nginx部署
    C# 按照比重来随机 [搬运微调]
    前端时间戳处理去年昨天当天基于dayjs
    记录第一次亲自部署.net core 3.0坑
    .net获取/修改配置文件/web.config
    遍历实体类属性获取键值
    Linq以本周和本月为条件的Sql,Liqn查询本周,Linq查询本月
    [基础累积] C#计算时间差
    CSS3自定义滚动条样式方法
    基础的多级菜单一个没见过的思路
  • 原文地址:https://www.cnblogs.com/xiaoziyao/p/15781300.html
Copyright © 2011-2022 走看看