Problem
Solution
鉴于Rayment的期望dp实在是太差了,他只好写一些套路的水题了……
什么叫期望的逆推呢。。?
那就是对于现在的状态S,我们去考虑它的所有后继状态 T 1 , T 2 ⋯ T m {T_1,T_2\cdots T_m} T1,T2⋯Tm,且各个后继发生的概率是 p 1 , p 2 ⋯ p m p_1,p_2\cdots p_m p1,p2⋯pm和它们分别的转移代价 c 1 , c 2 ⋯ c m c_1,c_2\cdots c_m c1,c2⋯cm,那么就有 E ( S ) = ∑ i = 1 m ( E ( T i ) + c i ) p i E(S)=\sum_{i=1}^m (E(T_i)+c_i)p_i E(S)=∑i=1m(E(Ti)+ci)pi
比如我们来看个简单的例子,问一个正常的硬币期望抛多少次可以得到正面?我们设这个答案为x,那么 x = 0.5 ∗ ( 0 + 1 ) + 0.5 ( x + 1 ) x=0.5*(0+1)+0.5(x+1) x=0.5∗(0+1)+0.5(x+1),解方程可以得到 x = 2 x=2 x=2。
那么我们来看这道题,其实是两个不同的问题。
对于第一个问题,我们设 f [ i ] f[i] f[i]表示已经有i个连续相同的数字,离达到连续n个期望多少次。则有
f [ i ] = 1 m f [ i + 1 ] + m − 1 m f [ 1 ] + 1 f[i]=\frac 1 m f[i+1]+\frac {m-1} m f[1]+1 f[i]=m1f[i+1]+mm−1f[1]+1
~~按照套路,~~作差可得 m ( f [ i + 1 ] − f [ i ] ) = f [ i + 2 ] − f [ i + 1 ] m(f[i+1]-f[i])=f[i+2]-f[i+1] m(f[i+1]−f[i])=f[i+2]−f[i+1]
然后我们又有 f [ 0 ] − f [ 1 ] = 1 , f [ n ] = 0 f[0]-f[1]=1,f[n]=0 f[0]−f[1]=1,f[n]=0,上等比数列求和公式 a n s = f [ 0 ] = m n − 1 m − 1 ans=f[0]=\frac {m^n-1} {m-1} ans=f[0]=m−1mn−1
对于第二个问题,设 f [ i ] f[i] f[i]表示已经有i个连续不相同的数字,离达到连续n个期望多少次。
f [ i ] = m − i m f [ i + 1 ] + ∑ j = 1 i f [ j ] m f[i]=\frac {m-i} m f[i+1]+\frac {\sum_{j=1}^i f[j]} {m} f[i]=mm−if[i+1]+m∑j=1if[j]
我们又作差
f [ i ] − f [ i + 1 ] = m − i − 1 m ( f [ i + 1 ] − f [ i + 2 ] ) f[i]-f[i+1]=\frac {m-i-1} m(f[i+1]-f[i+2]) f[i]−f[i+1]=mm−i−1(f[i+1]−f[i+2])
不会用求和公式了,直接暴力 O ( n ) O(n) O(n)搞一搞就行了。
顺带一提,这个数据不知为什么用read会TLE,改成scanf就可以了。
Code
#include <cstdio>
#include <cmath>
#define rg register
using namespace std;
typedef long long ll;
template <typename Tp> inline int getmin(Tp &x,Tp y){return y<x?x=y,1:0;}
template <typename Tp> inline int getmax(Tp &x,Tp y){return y>x?x=y,1:0;}
template <typename Tp> inline void read(Tp &x)
{
x=0;int f=0;char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
if(ch=='-') f=1,ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
if(f) x=-x;
}
int z,m,n,op;
double ans,tmp;
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
#endif
while(~scanf("%d",&z))
{
while(z--)
{
scanf("%d%d%d",&op,&m,&n);
if(!op) ans=(pow(m,n)-1.0)/(m-1.0);
else
{
tmp=1.0;ans=0.0;
for(rg int i=0;i<n;i++) tmp*=1.0*m/(m-i),ans+=tmp;
}
printf("%.9lf\n",ans);
}
}
return 0;
}