-
题意 :有n个节点,它们在一条边上排列,每个排列的权重和是从1-2-……-n的距离和,求n!个排列权重和的总和。
-
思路 :对于每一个排列,求从1走到n的路径和,考虑每个点对的贡献。
1)对于一个点对,在n!个排列中,他们相邻时有2 * (n-2)!种情况: 因为他们相邻,即排列组合中的捆绑法,其他n-2个点全排列是 (n-2)!,他们内部排列是 2!。而这样的相邻情况一共有n-1种,所以每个点对所有排列中的相邻次数是 2 * (n-1)!。
对于上述的解释 :
例如 有四个点 1 2 3 4,考虑 1 2点对相邻的情况
如图,四个位置,1 2点对在前两个位置时。1 2之间可以互换,其他两个位置全排列,所以一共 2 * (n-2)! = 2 * (4-2)!。
而1 2点对可以在第二第三个位置,也可以在第三第四个位置,一共有n-1个位置,所以一共出现了 2 * (n-1)! = 2*3! = 12次。2)求出所有点对相邻的次数,再求出任意两点之间距离的和,再乘以次数即可。求任意两点距离和可以看这道题,树形dp的基础应用
https://blog.csdn.net/qq_39763472/article/details/82894446 -
代码 :
#include "bits/stdc++.h"
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
#define fori(i,l,u) for(int i = l;i < u;i++)
#define forj(j,l,u) for(int j = l;j < u;j++)
#define F first
#define S second
#define pb push_back
#define mk make_pair
typedef long long ll;
typedef pair<int, int> pi;
typedef pair<string, int> ps;
typedef vector<int> vi;
typedef vector<string> vs;
typedef vector<pi> vpi;
const int maxn = 2e5 + 6;
const int INF = 1e9 + 7;
ll n;
ll x,y,w;
ll dp[maxn],sum[maxn];
typedef struct{
ll v;
ll w;
}node;
vector<node> tree[maxn];
void init(){
mem(dp,0);
mem(sum,0);
fori(i, 1, n+1) tree[i].clear();
}
void dfs(ll cur,ll ft){
sum[cur] = 1;
fori(i, 0, tree[cur].size()){
ll son = tree[cur][i].v;
ll len = tree[cur][i].w;
if (son == ft) {
continue;
}
dfs(son, cur);
sum[cur] += sum[son];
dp[cur] = (dp[cur] + (dp[son] + sum[son] * (n-sum[son])%INF * len %INF) ) % INF;
}
}
int main()
{
// freopen("1.txt", "r", stdin);
while(~scanf("%lld",&n)){
init();
fori(i, 1, n){
scanf("%lld%lld%lld",&x,&y,&w);
node t1,t2;
t1.v = x;
t1.w = w;
t2.v = y;
t2.w = w;
tree[x].pb(t2);
tree[y].pb(t1);
}
dfs(1, -1);
ll num = 1;
for (ll i = 1; i < n ; i++) {
num = num * i % INF;
}
ll ans = 2 * dp[1] %INF* num %INF;
printf("%lld\n",ans);
}
return 0;
}
- 遇到的问题 :思路还是很清晰的,但是实现起来就有细节问题。
1)还是scanf recommend,cin没试过,不过肯定wa。数据太大。
2)第一次提交wa了,看到执行到1w k内存的时候wa的(这也是杭电的好处,如果现场赛就没法看出来了),所以肯定是大数据的时候出错,所以改成了所有的变量都是long long,但还是wa。突然想起来需要mod 1e9 + 7,但是需要的地方很多 :
首先是求(n-1)!需要mod,然后答案也需要mod,而且不能mod一次,因为中间结果也会超范围。
然后是
树形dp中间结果,需要mod INF。sum因为是以某个节点为根的子树的节点数,所以最多1e5,len就是1e9的最大范围了,所以需要mod,dp也会超,所以相加需要mod。。因为mod问题wa了10次。。大家注意。。