題意:
長度爲n的非遞減序列,現已知其中m個位置上數的位置(一定知道首尾的數字),求還原該序列有多少種方案數,序列各位和的期望是多少?
分析:
每兩個已知位置之間的問題相互獨立,
則需要解決一個MIN>=A[I], MAX<=A[I+1]的非遞減序列有多少種方案,序列和的期望是多少?
方案數:
因爲N個數的非遞減排列數只有一種,即這是一個組合問題。
可對應組合數學中“N種物品中選出K個,有多少種方案數”,C(N+K-1, N-1).
注:該模型用隔板法理解,將這K個物品通過插入N-1個隔板分成N份,即在最終的N+K-1個位置中選N-1個放上隔板。
期望:
所有方案數中每個可選數的出現次數是相同的,即滿足A[I]到A[I+1]上的均勻分佈,每位上的期望爲(A[I]+A[I+1])/2;
那K個位置的期望爲 k*(A[I]+A[I+1])/2;
組合數計算:
C(N,K)= N! / ( K! * ( N - K )! ),通過求逆元計算。
當P爲素數時,a的逆元 = [ a ^ (p-2) ] % p
具體實現:
RE了一發,因爲沒有考慮組合數最大是N+K+1爲底的,開成了10^6
#include <cstdio>
#include <algorithm>
#include <queue>
#include <cstring>
#include <cmath>
#include <set>
#include <vector>
#define mod 1000000009
using namespace std;
typedef long long LL;
LL a[2000],b[2000];
LL jc[2000100];
void init()
{
jc[0]=1;
for(int i=1;i<=2000010;i++)
jc[i]=jc[i-1]*i%mod;
}
LL quick_pow(LL n,LL m)
{
LL ans=1;
while(m>0)
{
if(m&1)
ans=(ans*n)%mod;
n=(n*n)%mod;
m>>=1;
}
return ans;
}
LL get_rev(LL n)
{
return quick_pow(n,mod-2);
}
LL cal(LL n,LL m)
{
return jc[n]*get_rev(jc[m])%mod*get_rev(jc[n-m])%mod;
}
int main()
{
LL n,m;
int T;
init();
scanf("%d",&T);
for(int t=1;t<=T;t++)
{
scanf("%lld %lld",&n,&m);
for(int i=0;i<m;i++)
scanf("%lld",&a[i]);
for(int i=0;i<m;i++)
scanf("%lld",&b[i]);
LL ca=1;
double sum=0;
for(int i=0;i<m-1;i++)
{
sum+=b[i];
LL num=b[i+1]-b[i]+1;
LL k=a[i+1]-a[i]-1;
if(k==0) continue;
ca=(ca*cal(num+k-1,min(k,n-1)))%mod;
sum+=(double)k*(b[i]+b[i+1])/2;
}
sum+=b[m-1];
printf("Case #%d: %lld %.3lf\n",t,ca,sum);
}
return 0;
}