• 【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;
    }
    
    
  • 相关阅读:
    【HDOJ】2774 Shuffle
    【POJ】2170 Lattice Animals
    【POJ】1084 Square Destroyer
    【POJ】3523 The Morning after Halloween
    【POJ】3134 Power Calculus
    【Latex】如何在Latex中插入伪代码 —— clrscode3e
    【HDOJ】4801 Pocket Cube 的几种解法和优化
    【HDOJ】4080 Stammering Aliens
    【HDOJ】1800 Flying to the Mars
    SQL语法
  • 原文地址:https://www.cnblogs.com/cjyyb/p/9155943.html
Copyright © 2020-2023  润新知