HDU 6827 Road To The 3rd Building(前缀和+乘法逆元+数学推导)

原题链接:Road To The 3rd Building

题面:

HDU 6827 Road To The 3rd Building(前缀和+乘法逆元+数学推导)_第1张图片

题目大意:

n n n 棵银杏树,每棵树都有可爱价值,当从第 i i i 棵树走到第 j j j 棵树,则他们的平均可爱价值为 1 j − i + 1 ∑ k = i j s [ i ] \cfrac{1}{j-i+1}\sum_{k=i}^{j}s[i] ji+11k=ijs[i]
最后求这些可爱价值的数学期望。即 ∑ i = 1 n E [ i ] \sum_{i=1}^{n}E[i] i=1nE[i]

数学推导:

我们可以先考虑每一个数对于期望值的贡献。
n = 4 n=4 n=4 来举例:

  • i = 1 i=1 i=1 s u m [ 1 ] ∗ 1 − 1 + s u m [ 2 ] ∗ 2 − 1 + s u m [ 3 ] ∗ 3 − 1 + s u m [ 4 ] ∗ 4 − 1 sum[1]*1^{-1}+sum[2]*2^{-1}+sum[3]*3^{-1}+sum[4]*4^{-1} sum[1]11+sum[2]21+sum[3]31+sum[4]41
  • i = 2 i=2 i=2 ( s u m [ 2 ] − s u m [ 1 ] ) ∗ 1 − 1 + ( s u m [ 3 ] − s u m [ 1 ] ) ∗ 2 − 1 + ( s u m [ 4 ] − s u m [ 1 ] ) ∗ 3 − 1 (sum[2]-sum[1])*1^{-1}+(sum[3]-sum[1])*2^{-1}+(sum[4]-sum[1])*3^{-1} (sum[2]sum[1])11+sum[3]sum[1])21+(sum[4]sum[1])31
  • i = 3 i=3 i=3 ( s u m [ 3 ] − s u m [ 2 ] ) ∗ 1 − 1 + ( s u m [ 4 ] − s u m [ 2 ] ) ∗ 2 − 1 (sum[3]-sum[2])*1^{-1}+(sum[4]-sum[2])*2^{-1} (sum[3]sum[2])11+(sum[4]sum[2])21
  • i = 4 i=4 i=4 ( s u m [ 4 ] − s u m [ 3 ] ) ∗ 1 − 1 (sum[4]-sum[3])*1^{-1} (sum[4]sum[3])11
  • 其中, s u m [ i ] sum[i] sum[i] s [ 1 ] s[1] s[1] s [ i ] s[i] s[i] 的前缀和,带有 − 1 -1 1 次方的数为乘法逆元。希望读者跟着思路自己推一下。

全部相加后,可以得到这样一个式子: C u t e L e v e l _ s u m [ 4 ] = s u m [ 1 ] ∗ ( 1 − 1 − 1 − 1 − 2 − 1 − 3 − 1 ) + s u m [ 2 ] ∗ ( 2 − 1 + 1 − 1 − 1 − 1 − 2 − 1 ) + s u m [ 3 ] ∗ ( 3 − 1 + 2 − 1 + 1 − 1 − 1 − 1 ) + s u m [ 4 ] ∗ ( 4 − 1 + 3 − 1 + 2 − 1 + 1 − 1 ) CuteLevel\_sum[4]=sum[1]*(1^{-1}-1^{-1}-2^{-1}-3^{-1})\\+sum[2]*(2^{-1}+1^{-1}-1^{-1}-2^{-1})\\+sum[3]*(3^{-1}+2^{-1}+1^{-1}-1^{-1})\\+sum[4]*(4^{-1}+3^{-1}+2^{-1}+1^{-1}) CuteLevel_sum[4]=sum[1](11112131)+sum[2](21+111121)+sum[3](31+21+1111)+sum[4](41+31+21+11)
数学归纳一下,可以很明显的推出一个式子: C u t e L e v e l _ s u m [ n ] = ∑ i = 1 n s u m [ i ] ∗ ( i n v _ s u m [ i ] − i n v _ s u m [ n − i ] ) CuteLevel\_sum[n]=\begin{matrix} \sum_{i=1}^n sum[i]*(inv\_sum[i]-inv\_sum[n-i]) \end{matrix} CuteLevel_sum[n]=i=1nsum[i](inv_sum[i]inv_sum[ni])
其中, C u t e L e v e l _ s u m [ n ] CuteLevel\_sum[n] CuteLevel_sum[n] 是下标从 1 1 1 n n n 的可爱值的总和, i n v _ s u m [ i ] inv\_sum[i] inv_sum[i] 是从 1 1 1 i i i 的乘法逆元前缀和。

最后,求一下所有的可爱值个数就行了,总数为: t o t = n ∗ ( n + 1 ) 2 tot=\cfrac{n*(n+1)}{2} tot=2n(n+1)。期望为: E [ n ] = C u t e L e v e l _ s u m [ n ] t o t E[n]=\cfrac{CuteLevel\_sum[n]}{tot} E[n]=totCuteLevel_sum[n]

附上标准题解:

HDU 6827 Road To The 3rd Building(前缀和+乘法逆元+数学推导)_第2张图片

代码:
#include 
#define sc scanf
#define pf printf
using namespace std;

typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> PII;
const int N = 2e5 + 10, M = 2e4 + 10;
const int INF = 0x3f3f3f3f;
const double eps = 1e-7;
const int mod = 1e9 + 7;

LL inv[N], invs[N], sum[N], s[N];

LL qmi(LL a, LL b)
{
    LL ans = 1;
    for( ; b; b >>= 1) {
        if(b & 1)   ans = ans * a % mod;
        a = a * a % mod;
    }
    return ans;
}

void init()
{
    invs[0] = 0, invs[1] = 1, inv[1] = 1;
    for (int i=2;i<N;i++) inv[i] = (mod - mod/i) * inv[mod%i] % mod;
    for (int i=1;i<N;i++) invs[i] = (invs[i - 1] + inv[i]) % mod;
    return ;
}

void solve()
{
    int n;
    sc("%d", &n);
    for(int i = 1; i <= n; i++)  sc("%lld", &s[i]);
    sum[0] = 0;
    for(int i = 1; i <= n; i++)  sum[i] = (sum[i - 1] + s[i]) % mod;

    LL ans = 0;
    for(int i = 1; i <= n; i++)
        ans = (ans + (sum[i] * (invs[i] - invs[n - i])) % mod) % mod;

    LL tot = (1LL * n * (n + 1) / 2) % mod;
    ans = ans * qmi(tot, mod - 2) % mod;
    //这个做法,ans可能会模到负数去。
    //所以需要将ans取到正数上来。
    pf("%lld\n", (ans % mod + mod) % mod);
}

int main()
{
    init();
    int t; sc("%d", &t); while(t--) solve();
    return 0;
}

标程:
#include 
#define MAXN 200005
using namespace std;

const long long M=1000000007;

int T,n,a[MAXN];
long long inv[MAXN],sinv[MAXN],ans,C;

inline long long fpow(long long a,long long b)
{
	a%=M;long long r=1;
	for (;b;b>>=1,(a*=a)%=M) if (b&1) (r*=a)%=M;
	return r;
}

void init(int n)
{
	inv[1]=1;
	for (int i=2;i<=n;i++) inv[i]=(M-M/i)*inv[M%i]%M;
	for (int i=1;i<=n;i++) sinv[i]=(sinv[i-1]+inv[i])%M;
	return ;
}

inline void Solve()
{
	scanf("%d",&n);C=ans=0;
	for (int i=1;i<=n;i++) scanf("%d",&a[i]);
	for (int i=1,p=n>>1;i<=p;i++)
	{
		long long cov=i;
		cov+=i*(sinv[n-i]-sinv[i]+M)%M;cov%=M;
		(C+=i*inv[n-i+1]%M)%=M;(cov+=C)%=M;
		(ans+=a[i]*cov%M)%=M;(ans+=a[n+1-i]*cov%M)%=M;
	}
	if (n&1)
	{
		long long cov=0;
		for (int i=1;i<=n;i++) (cov+=min(i,n+1-i)*inv[i]%M)%=M;
		(ans+=cov*a[(n>>1)+1]%M)%=M;
	}
	printf("%lld\n",ans*fpow(1LL*n*(n+1)/2,M-2)%M);
	return ;
}

int main()
{
	init(200000);
	scanf("%d",&T);
	while (T--) Solve();
	return 0;
}

你可能感兴趣的:(算法,数学建模)