【Luogu1291】百事世界杯之旅(动态规划,数学期望)

题面

洛谷

题解

f[i] 表示已经集齐了 i 个名字的期望

现在有两种方法:
先说我自己的:

f[i]=f[i1]+1+(1p)(1p1+2p2+....)

其中 p=i1n
为什么,很简单
首先要多收集一个,期望 +1 是显然的
但是还可能一直买到了已经有的名字中的一个
p 的概率多买一个
p2 的概率多买两个
这样无穷的算下去
然后对于后面那个式子
做两次错位相减(其实就是一个无穷级数)
推出
f[i]=f[i1]+1+i1n(i1)

然后递推就行了

第二种方法:
fdf 的方法(感觉这种方法也很强呀)
f[i] 表示已经收集了 i
收集到 n 个需要的期望

f[i]=in(f[i]+1)+nin(f[i+1]+1)

ninf[i]=ninf[i+1]+1

f[i]=f[i+1]+nni

初值: f[n]=0
倒着算即可

贴上我自己的代码

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define ll long long
#define RG register
inline int read()
{
    RG int x=0,t=1;RG char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=-1,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return x*t;
}
int n;
int ws(ll x)
{
    int ret=0;
    while(x)++ret,x/=10;
    return ret;
}
struct Num
{
    ll a,b;
    void easy()
        {
            ll d=__gcd(a,b);
            a/=d;b/=d;
        }
    void output()
        {
            easy();
            if(b==1){printf("%lld\n",a);return;}
            ll k=a/b;a-=k*b;
            int blk=ws(k),ss=max(ws(a),ws(b));
            for(int i=1;i<=blk;++i)putchar(' ');
            printf("%lld\n",a);
            printf("%lld",k);
            for(int i=1;i<=ss;++i)putchar('-');putchar('\n');
            for(int i=1;i<=blk;++i)putchar(' ');
            printf("%lld\n",b);
        }
}f[50];
Num operator+(Num a,Num b)
{
    ll d=a.b/__gcd(a.b,b.b)*b.b;
    return (Num){a.a*(d/a.b)+b.a*(d/b.b),d};
}
Num operator*(Num a,Num b)
{
    Num c=(Num){a.a*b.a,a.b*b.b};
    c.easy();
    return c;
}
int main()
{
    n=read();
    f[0]=(Num){0,1};
    for(int i=1;i<=n;++i)
    {
        f[i]=f[i-1]+(Num){1,1};
        f[i]=f[i]+(Num){i-1,n-i+1};
    }
    f[n].output();
    return 0;
}

你可能感兴趣的:(各省省选,DP,动态规划)