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[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;
}
};