zoukankan      html  css  js  c++  java
  • 【BZOJ1063】【NOI2008】道路设计(动态规划)

    【BZOJ1063】【NOI2008】道路设计(动态规划)

    题面

    BZOJ

    题解

    发现每个点最多只能被修一次等价于每个点最多只能和两条铁路相邻
    考虑一个(dp)
    (f[i][0/1/2])表示以(i)为根,当前点与他的儿子已经有(0/1/2)条铁路相邻的方案数
    转移也很简单,考虑每个儿子,枚举是修还是不修就行了
    这样的复杂度是(O(n))

    这样的前提是不需要计算答案的方案数,我们可以很容易想出来
    现在考虑如何计算方案数。
    考虑一下答案的范围,如果我们把这棵树进行树链剖分
    重链视为修铁路,那么任意一个点跳轻边的次数不会超过(log)
    所以,答案一定不会超过(log)
    这样子在做的时候把答案限制也加上就好了
    (f[i][j][k])表示以(i)为根的子树,答案为(j)
    当前点与(k)条铁路相邻的方案数,其中(kin{0,1,2})
    转移和前面没有太多的区别,只需要注意一下答案那一位的变化就行了
    时间复杂度(O(nlogn))
    注意一下这道题目要怎么取模

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<set>
    #include<map>
    #include<vector>
    #include<queue>
    using namespace std;
    #define ll long long
    #define RG register
    #define MAX 100100
    inline int read()
    {
        RG int x=0,t=1;RG char ch=getchar();
        while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
        if(ch=='-')t=-1,ch=getchar();
        while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
        return x*t;
    }
    struct Line{int v,next;}e[MAX<<1];
    int h[MAX],cnt=1;
    inline void Add(int u,int v){e[cnt]=(Line){v,h[u]};h[u]=cnt++;}
    int n,m,MOD;
    int f[MAX][20][3];
    void add(int &x,int y){x+=y;if(x>MOD)x-=MOD;}
    int mod(ll x){if(x!=0&&x%MOD==0)return MOD;return x%MOD;}
    void dfs(int u,int ff)
    {
    	for(int i=0;i<20;++i)f[u][i][0]=1;--n;
    	for(int i=h[u];i;i=e[i].next)
    	{
    		int v=e[i].v;if(v==ff)continue;
    		dfs(v,u);
    		for(int ans=0;ans<19;++ans)
    		{
    			int f0=0,f1=0;
    			if(ans)f0=mod(1ll*f[v][ans-1][0]+f[v][ans-1][1]+f[v][ans-1][2]);
    			f1=mod(1ll*f[v][ans][0]+f[v][ans][1]);
    			f[u][ans][2]=mod(1ll*f[u][ans][2]*f0+1ll*f[u][ans][1]*f1);
    			f[u][ans][1]=mod(1ll*f[u][ans][1]*f0+1ll*f[u][ans][0]*f1);
    			f[u][ans][0]=mod(1ll*f[u][ans][0]*f0);
    		}
    	}
    }
    int main()
    {
    	n=read();m=read();MOD=read();
    	for(int i=1;i<=m;++i)
    	{
    		int u=read(),v=read();
    		Add(u,v);Add(v,u);
    	}
    	dfs(1,0);
    	if(n){puts("-1");puts("-1");return 0;}
    	int ans=1e9,tot=0;
    	for(int i=0;i<20;++i)
    		if(f[1][i][0]||f[1][i][1]||f[1][i][2]){ans=i;break;}
    	tot=mod(1ll*f[1][ans][0]+f[1][ans][1]+f[1][ans][2])%MOD;
    	printf("%d
    %d
    ",ans,tot);
    	return 0;
    }
    
    
  • 相关阅读:
    排序
    最小栈
    移除链表元素
    回文链表
    maven自动建立目录骨架
    maven的结构和构建命令
    递归
    链表的中间结点
    括号匹配
    软件工程个人作业01
  • 原文地址:https://www.cnblogs.com/cjyyb/p/9155943.html
Copyright © 2011-2022 走看看