[BZOJ5305] [HAOI2018] 苹果树

题目链接

BZOJ:https://lydsy.com/JudgeOnline/problem.php?id=5305

洛谷:https://www.luogu.org/problemnew/show/P4492

LOJ:https://loj.ac/problem/2526

Solution

神仙计数题...

对于一棵固定的树,对于每一条边的贡献很容易算,如果这条边较深的点为\(v\),那么这条边对答案的贡献就是\(2sz_v(n-sz_v)\)

那么我们反过来考虑,我们\(O(n^2)\)的枚举这条边的情况,即枚举深度较小的点的编号和较大的点的\(size\),然后统计一条这样的边在所有情况中出现了多少次。

首先我们硬点加点的时候是按编号顺序从小到达的加的,这对答案无影响。

设当前枚举到的点为\(i\),深度较大的点\(size\)\(j\),我们分成三部分统计。

  • \(1\sim i\)的点没有限制,有\(i!\)种情况。
  • 然后剩下了\(n-i\)个点,我们要选出\(j\)个放在\(i\)下面,这\(j\)个点连的时候也没有限制,那么就是\(\binom{n-i}{j}j!\)种情况。
  • 除开这些点剩下还有\(n-i-j\)个点,第一次有\(i\)种选法,第二次有\(i+1\)种...最后一次有\(n-i-j+1\)种选法,一共就是\(\prod_{k=i}^{n-i-j+1}k\) 种。

那么总的贡献就是:
\[ ans=\sum_{i=1}^{n}\sum_{j=1}^{n-i}2j(n-j)\cdot i!\cdot j!\binom{n-i}{j}\cdot \prod_{k=i}^{n-j-1}k \]
化简一下:
\[ \begin{align} ans=&\sum_{i=1}^{n}i!\cdot 2\sum_{j=1}^{n-i}j(n-j)\cdot j!\binom{n-i}{j}\prod_{k=i}^{n-j-1}k\\ =&\sum_{i=1}^{n}i!\cdot 2\sum_{j=1}^{n-i}j(n-j)\cdot \frac{(n-i)!}{(n-i-j)!}\prod_{k=i}^{n-j-1}k\\ =&\sum_{i=1}^{n}i!\cdot 2\sum_{j=1}^{n-i}j(n-j)\cdot \left(\prod_{k=n-i-j+1}^{n-i}k\right)\left(\prod_{k=i}^{n-j-1}k\right) \end{align} \]
由于没有逆元,可以预处理出\(s[i][j]=\prod_{k=i}^{j}k\),时间复杂度\(O(n^2)\)

#include<bits/stdc++.h>
using namespace std;

void read(int &x) {
    x=0;int f=1;char ch=getchar();
    for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
    for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
}

void print(int x) {
    if(x<0) putchar('-'),x=-x;
    if(!x) return ;print(x/10),putchar(x%10+48);
}
void write(int x) {if(!x) putchar('0');else print(x);putchar('\n');}

#define lf double
#define ll long long 

const int maxn = 2e3+10;
const int inf = 1e9;
const lf eps = 1e-8;

int s[maxn][maxn],n,mod,ans;

int main() {
    read(n),read(mod);
    for(int i=1;i<=n;i++) {
        s[i][i]=i;
        for(int j=i+1;j<=n;j++) s[i][j]=1ll*s[i][j-1]*j%mod;
        for(int j=0;j<i;j++) s[i][j]=1;
    }
    for(int i=1;i<=n;i++) {
        int res=0;
        for(int j=1;j<=n-i;j++) res=(res+1ll*j*(n-j)%mod*s[n-i-j+1][n-i]%mod*s[i][n-j-1]%mod)%mod;
        ans=(ans+2ll*s[1][i]%mod*res%mod)%mod;
    }write(ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/hbyer/p/10647406.html