1. 程式人生 > 實用技巧 >hdu 6827 Road To The 3rd Building

hdu 6827 Road To The 3rd Building

題意:

t組輸入,每一組一個n,然後後面是n個樹的值(我們放到陣列v裡面),你需要從[1,n]這個區間內挑選出來兩個數i,j,你需要保證i<=j,之後你要求一下v[i]+v[i+1]+...+v[j],然後把這個和除於j-i+1(也就是求平均值),最後答案要求的是這個平均值的期望,我們可以算出來有多少對(i,j),我們設有sum對,然後讓每一個平均值乘於1/sum,把這個都加到一起就可以了

題解:

sum的求法就是n*(n-1)/2

然後

我們可以列舉區間大小,從1列舉到n,上圖是區間長度為1

藍線中間的是,區間長度為1的時候區間內的數,如果區間長度為2的時候,那麼藍線中間的就是

1234

2345

藍線上下兩側的就是把它們都補全之後的模樣,我們只需要用v的字首和陣列w,讓w[n]乘於一個數然後減去上下兩側的就可以

總之就是找規律

程式碼:

#include<stack>
#include<queue>
#include<map>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define fi first
#define se second
using namespace std;
typedef 
long long ll; const int maxn=2e5+10; const int mod=1e9+7; ll v[maxn],p[maxn],p2[maxn],p_pre[maxn],p_suf[maxn]; ll ksc(ll a, ll b) { ll ans = 0; while( b > 0 ) { if( b&1 ) ans = (ans + a) % mod; a = ( a + a ) % mod; b >>= 1; } return ans; } ll ppow(ll a,ll b) { ll ans
=1; while(b) { if(b&1) ans=(ans*a)%mod; a=(a*a)%mod; b>>=1; } return ans; } //void init() //{ // ll ans = 0; // for (ll i = 1; i <= 6000001; i++) // { // ll x = ((i * i) % mod); // ans = (ans + (ppow(x, mod - 2) % mod)); // dp[i] = (ans * 3) % mod; // } //} int main() { ll t; scanf("%lld",&t); while(t--) { memset(v,0,sizeof(v)); memset(p,0,sizeof(p)); memset(p2,0,sizeof(p2)); memset(p_pre,0,sizeof(p_pre)); memset(p_suf,0,sizeof(p_suf)); ll n,result=0,sum; scanf("%lld",&n); sum=(n*(n+1))/2; sum%=mod; for(ll i=1; i<=n; ++i) { scanf("%d",&v[i]); p[i]=(p[i-1]+v[i])%mod; } p2[n]=v[n]; for(ll i=n-1; i>=1; --i) { p2[i]=(p2[i+1]+v[i])%mod; } for(ll i=1; i<=n; ++i) { p_pre[i]=(p[i]+p_pre[i-1])%mod; } p_suf[n+1]=0; p_suf[n]=p2[n]; for(ll i=n-1; i>=1; --i) { p_suf[i]=(p2[i]+p_suf[i+1])%mod; } for(ll i=1; i<=n; ++i) { result = (result + (((((i*p[n])%mod)-p_pre[i - 1]-p_suf[n-i+2]+mod) % mod) * ppow(i, mod - 2)%mod))%mod; } printf("%lld\n",((result%mod)*ppow(sum,mod-2))%mod); } return 0; }