WalkOverATree
题意:给你一棵树,有个人在节点0,现在问你,这个人走L步,最多能访问多少个不同的节点,一个节点可以被走多次,但只算一次。
题解:这个问题的关键在于,每个点最多走两次,这是因为我要么一次性走到这个点,要么从这个点回去走其他的点,不可能出现走三次的情况,这里需要细想清楚。
那么我们可以得到这样的一个算法:枚举一条一次性走的路径,想象成主干道,这个主干道上连接有若干旁道,那么我可以访问这个旁道上的某些点,然后返回主干道,这些点我一共要用两倍的步数才能走完,因为要返回主干道,并且容易发现,这对任意一个旁道都是一样的。
设d[i]表示i离根节点的距离,ans是最终的答案,那么ans=max(ans,d[i]+1+min(n-d[i]-1,(L-d[i])/2))。
SumOverPermutations
题意:
有个奇葩,组合数学很渣,老师问他:无限个n种颜色的球放在n个有顺序的盒子中,每个盒子放一个,相邻盒子的球的颜色不同,有多少种方法。这个奇葩给了个奇葩的解答,他说这和放的顺序有关,比如有三个盒子,三种颜色的球,若放的顺序是 1 2 3,那么答案就是3×2×2,若放的顺序是 1 3 2,那么答案就是3×3×1。更一般的,他认为,若一个位置的左侧和右侧都被放了,那么现在有(n-2)种可能性,若只有一侧被放了,那么有(n-1)种可能性,若两侧都没放,那么有n种可能性。我们知道这是明显错误的,但是,题目就是问你,给你个n,这n!种放的顺序按照这个奇葩的算法得到的答案是多少。
题解:
令$dp[i]$表示$n$种颜色放在$i$个盒子中,答案是多少。那么转移就只有两种情况:
一种是将第$i$个球放在边界上,这种的转移是$dp[i]=2*dp[i-1]*(n-1)$,第一项的2表示左右两个边界,第二项$dp[i-1]$表示$i-1$时的情况,第三项$n-1$表示由于第$i$个球在边界,所以只乘$n-1$
另外一种是将第$i$个球放在中间某个位置,假设其左侧有$j$个球,那么转移必然是
$$dp[i]=sumlimits_{j=1}^{i-2}C_{i-1}^j*dp[j]*dp[i-j-1]*(n-2)$$
所以总的转移是
$$dp[i]=(sumlimits_{j=1}^{i-2}C_{i-1}^j*dp[j]*dp[i-j-1]*(n-2))+2*dp[i-1]*(n-1)$$
答案显然是$dp[n]$
long long dp[MAX_N]; long long mod=1000000007; long long C[MAX_N][MAX_N]; class SumOverPermutations { public: int findSum(int n) { C[0][0]=1; for(int i=1;i<=n;i++) for(int j=0;j<=i;j++) C[i][j]=(j==0?1:C[i-1][j-1]+C[i-1][j])%mod; dp[1]=n%mod; dp[2]=n%mod*(n-1)%mod*2%mod; for(int i=3;i<=n;i++){ dp[i]=2%mod*(n-1)%mod*dp[i-1]%mod; for(int j=1;j<=i-2;j++) dp[i]=(dp[i]+C[i-1][j]%mod*dp[j]%mod*dp[i-j-1]%mod*(n-2)%mod)%mod; } return dp[n]%mod; } };