• 2019.10.1 qbxt模拟题


    第一题

    考虑树上(DP),f[i][j][0/1]表示以(i)为根的子树,入读为零点的个数为(j),点(i)的入度为(0)/不为(0)时的方案数

    转移的时候考虑(u)的一个子树(v)的贡献,分类讨论边((u,v))的两个方向的两个方案,具体的转移方程看代码

    记录子树size,利用“刷表法”,只进行有用的转移,复杂度(O(n^2))

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #define LL long long
    using namespace std;
    
    const int MAXN=5010;
    const int MOD=1000000007;
    const int ch_top=4e7+3;
    char ch[ch_top],*now_r=ch-1;
    
    inline int read(){
    	while(*++now_r<'0');
    	register int x=*now_r-'0';
    	while(*++now_r>='0') x=x*10+*now_r-'0';
    	return x;
    }
    
    int n,m;
    LL f[MAXN][MAXN][2];
    
    int Head[MAXN],num;
    struct NODE{
    	int to,nxt;
    } e[MAXN<<1];
    
    inline void add(int x,int y){
    	e[++num].to=y;
    	e[num].nxt=Head[x];
    	Head[x]=num;
    }
    
    LL g[MAXN][2];
    int sz[MAXN];
    inline void dfs(int u,int fa){
    	sz[u]=f[u][1][0]=1;
    	for(int i=Head[u];i;i=e[i].nxt){
    		int v=e[i].to;
    		if(v==fa) continue;
    		dfs(v,u);
    		for(int j=0;j<=sz[u]+sz[v];++j) g[j][0]=g[j][1]=0;
    		for(int j=0;j<=sz[u];++j)
    			for(int k=1;k<=sz[v];++k){
    				g[j+k-1][1]+=f[u][j][0]*(f[v][k][0]+f[v][k][1]);
    				g[j+k-1][1]+=f[u][j][1]*f[v][k][0];
    				g[j+k-1][0]+=f[u][j][0]*f[v][k][0];
    				g[j+k][1]+=f[u][j][1]*(f[v][k][1]*2+f[v][k][0]);
    				g[j+k][0]+=f[u][j][0]*f[v][k][1];
    				g[j+k-1][1]%=MOD; g[j+k-1][0]%=MOD;
    				g[j+k][0]%=MOD; g[j+k][1]%=MOD;
    			}
    		for(int j=0;j<=sz[u]+sz[v];++j)
    			f[u][j][0]=g[j][0],f[u][j][1]=g[j][1];
    		sz[u]+=sz[v];
    	}
    }
    
    signed main()
    {
    	fread(ch,1,ch_top,stdin);
    	n=read(); m=read();
    	if(m>=n){
    		puts("0");
    		return 0;
    	}
    	int x,y;
    	for(int i=1;i<n;++i){
    		x=read(); y=read();
    		add(x,y); add(y,x);
    	}
    	dfs(1,0);
    	printf("%lld
    ",(f[1][m][1]+f[1][m][0])%MOD);
    	return 0;
    }
    /*
    9 4
    1 2
    2 9
    1 3
    3 4
    3 5
    4 8
    5 6
    5 7
    
    4 2
    1 2
    1 3
    2 4
    */
    

    第二题

    不妨设一个数(x)(1),可以进行两种操作:

    (x=x<<1),1的个数不增加,即代价为0

    (x=x<<1|1),1的个数+1,即代价为1

    当x为n的倍数且代价最小时即为答案,考虑最后的答案是一个(n)的倍数,不妨利用这个性质,将所有整数对(n)取模,其中为0的数可以作为答案,那么问题就转化为了1->0的最短路

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<queue>
    using namespace std;
    
    const int MAXN=1000010;
    
    inline int read(){
    	int x=0; char c=getchar();
    	while(c<'0') c=getchar();
    	while(c>='0') x=(x<<3)+(x<<1)+c-'0',c=getchar();
    	return x;
    }
    
    int T,n,dis[MAXN];
    deque<int> que;
    
    int main()
    {
    	T=read();
    	while(T--){
    		n=read();
    		memset(dis,0x3f,sizeof(dis));
    		dis[1]=1;
    		que.clear();
    		que.push_back(1);
    		while(!que.empty()){
    			int u=que.front();
    			if(u==0) break;
    			que.pop_front();
    			int v=u*2%n;
    			if(dis[v]>dis[u]){
    				dis[v]=dis[u];
    				que.push_front(v);
    			}
    			v=(v+1)%n;
    			if(dis[v]>dis[u]+1){
    				dis[v]=dis[u]+1;
    				que.push_back(v);
    			}
    		}
    		printf("%d
    ",dis[0]);
    	}
    	return 0;
    }
    

    第三题

    四元环计数模板

    类似于三元环计数,考虑将点划分权重,每条边从度数大的点到度数小的点定向,那么一个四元环就会变成这样

    灰边的方向有两种情况,但是每个四元环只能从一个点开始遍历找到

    爆搜两层就可以了

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    using namespace std;
    
    const int MAXN=100010;
    
    inline int read(){
    	int x=0; char c=getchar();
    	while(c<'0') c=getchar();
    	while(c>='0') x=(x<<3)+(x<<1)+c-'0',c=getchar();
    	return x;
    }
    
    int n,m,du[MAXN];
    long long Ans;
    
    int Head[MAXN],num;
    struct NODE{
    	int to,nxt;
    }e[MAXN<<1];
    
    inline void add(int x,int y){
    	e[++num].to=y;
    	e[num].nxt=Head[x];
    	Head[x]=num;
    }
    
    inline bool lk(int x,int y){
    	return du[x]>du[y]||(du[x]==du[y]&&x>y);
    }
    
    int vis[MAXN];
    
    int rt;
    inline void dfs(int u,int d){
    	if(d==0){
    		rt=u;
    		for(int i=Head[u];i;i=e[i].nxt){
    			int v=e[i].to;
    			if(lk(rt,v)) dfs(v,d+1);
    		}
    	}
    	else{
    		for(int i=Head[u];i;i=e[i].nxt){
    			int v=e[i].to;
    			if(lk(rt,v)){
    				Ans+=vis[v];
    				++vis[v];
    			}
    		}
    	}
    }
    
    inline void clr(int u,int d){
    	if(d==0){
    		rt=u;
    		for(int i=Head[u];i;i=e[i].nxt){
    			int v=e[i].to;
    			if(lk(rt,v)) clr(v,d+1);
    		}
    	}
    	else for(int i=Head[u];i;i=e[i].nxt)
    		++vis[e[i].to]=0;
    }
    
    int main(){
    	n=read(); m=read();
    	int x,y;
    	for(int i=1;i<=m;++i){
    		x=read(); y=read();
    		add(x,y); add(y,x);
    		++du[y]; ++du[x];
    	}
    	for(int i=1;i<=n;++i){
    		dfs(i,0);
    		clr(i,0);
    	}
    	printf("%lld
    ",Ans);
    	return 0;
    }
    
    
  • 相关阅读:
    反射API(二)
    反射API(一)
    session一二事
    自定义session的存储机制
    JavaScript 入门笔记
    PHP引用赋值
    九九乘法口诀表
    PHP流程控制笔记
    PHP函数总结 (七)
    Linux程序编辑器习题汇总
  • 原文地址:https://www.cnblogs.com/yjkhhh/p/11792848.html
Copyright © 2020-2023  润新知