1. 程式人生 > >洛谷比賽-P5011 水の造題-題解

洛谷比賽-P5011 水の造題-題解

題目地址與題意見連結


暴力就是 O ( k n ) O(k^n) 吧,不過 n

n 非常之大,有 1 0 1 0 6
10^{10^6}
(高精可怕.jpg)

但是我們發現,對於求期望,那麼就是概率 × \times 權值,所以我們可以先求出每種動作的貢獻:

每種動作出現在某個位置的概率為 1

k \frac{1}{k} ,貢獻為它的 v a l val ,總共有 n n 個可以出現的位置,所以貢獻為 i = 0 k 1 n × v a l i k \sum_{i=0}^{k-1}\frac{n\times val_i}{k}

接下來就是組合技的多的貢獻,每個組合技還會再貢獻一次,所以我們這樣來看:

每個組合技出現的概率為 1 k 2 \frac{1}{k^2} ,有 n 1 n-1 個可以出現的位置,每一種的貢獻為 v a l i + v a l ( i + 1 ) % k val_i+val_{(i+1)\%k} ,所以總貢獻為 i = 0 k 1 ( n 1 ) × ( v a l i + v a l ( i + 1 ) % k ) k 2 \sum_{i=0}^{k-1}\frac{(n-1)\times (val_i+val_{(i+1)\%k})}{k^2}

那麼我們 O ( k ) O(k) 的算一下就好啦,關於取模除法我們用費馬小定理逆元就可以了,因為 19491001 19491001 是個非常神奇且有巨大意義的質數,讀入 n n 時直接取模就好啦。

程式碼:

#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int M=1e6+10;
const ll Mod=19491001;
char s[M];
ll k,A[M],n,w;
ll inv_k,inv_k2;
void readin(){
	scanf("%s",s);
	int len=strlen(s);
	for(int i=0;i<len;i++){
		n=(n*10ll%Mod+(s[i]&15))%Mod;
	}	w=(n-1+Mod)%Mod;
}
ll Sqr(ll a){return a*a%Mod;}
ll fpow(ll a,ll b){
	ll ans=1;
	for(;b;b>>=1,a=(a*a)%Mod)if(b&1)ans=(ans*a)%Mod;
	return ans;
}
ll ans,sum1,sum2;
int main(){
	readin();
	scanf("%lld",&k);
	for(int i=0;i<k;i++){
		scanf("%lld",&A[i]);
		sum1=(sum1+A[i])%Mod;
		if(i)sum2=(sum2+(A[i-1]+A[i])%Mod)%Mod;
	}	sum2=(sum2+(A[0]+A[k-1])%Mod)%Mod;
	inv_k=fpow(k,Mod-2);
	inv_k2=(Sqr(inv_k)%Mod*w)%Mod;inv_k=(inv_k*n)%Mod;
	ans=(sum1*inv_k%Mod+sum2*inv_k2%Mod)%Mod;
	printf("%lld\n",ans);
	return 0;
}

下面還有一種解法,由 h d x r i e \rm hdxrie |Orz|提供:

我們先不考慮開頭結尾,那麼每個數都有前後:

我們考慮,對於一個位置的動作,它前後都不是組合技,那麼只會貢獻一次,那麼前面不是和它組合的概率為 k 1 k \frac{k-1}{k} ,後面不是和它組合的概率為 k 1 k \frac{k-1}{k} ,然後當前選這個的概率為 1 k \frac{1}{k} ,有 n 2 n-2 個位置可以這樣選,那麼貢獻為 ( k 1 k ) 2 × 1 k × v a l i × ( n 2 ) (\frac{k-1}{k})^2\times \frac{1}{k}\times val_i\times (n-2)

對於可以形成組合技的(這裡只考慮組成一個),那麼就是後面和它組合,前面不組合;或者前面組合,後面不組合。那麼貢獻就為 ( k 1 k × ( 1 k ) 2 × v a l i × 2 × ( n 2 ) ) × 2 \left(\frac{k-1}{k}\times \left(\frac{1}{k}\right)^2\times val_i\times 2\times (n-2)\right)\times 2 (這時 v a l i val_i 要算兩次貢獻,同樣還是有 n 2 n-2 個可以的位置)

對於前後都可以組合的,概率為 ( 1 k ) 3 \left(\frac{1}{k}\right)^3 ,所以貢獻為 ( 1 k ) 3 × v a l i × 3 × ( n 2 ) \left(\frac{1}{k}\right)^3\times val_i\times 3\times (n-2)