hdu 6827 Road To The 3rd Building
阿新 • • 發佈:2020-08-08
題意:
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; typedeflong 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; }