Sol
题目大意
有 n n 个不同的物品,得到其中一个物品的概率相同,问若要得到所有物品平均需要买几次
题解
貌似之前楼上的题解的公式虽然推的大概是对的,但是讲解是错的而且就连 的范围也是错的(真是尴尬)
我考虑的是以
f[i]
f
[
i
]
表示已经得到其中
i
i
个物品,还需得到然后所期望的平均次数,最后答案在
f[0]
f
[
0
]
中
那么,你可能会列出如下两种转移方程式
一:由
f[i−1]
f
[
i
−
1
]
推到
f[i]
f
[
i
]
二:由 f[i+1] f [ i + 1 ] 推到 f[i] f [ i ]
所以大家应该发现你考虑 正着推和 倒着推是不一样的,那么
Q:哪种方式才是对的呢
A:显然方式二啊
Q:qwq,大佬说说为什么吧
A:首先方案二中的
+1
才有道理,其本质是
in
i
n
+
n−in
n
−
i
n
=1
这才是正确的期望=贡献*概率,然而方案一中的 +1 + 1 毫无道理,你究竟是在计算 f[i] f [ i ] 还是 f[i−1] f [ i − 1 ] 时加的呢?
Q:好像还是不太懂啊
A:好吧,在终止状态唯一确定时,你会发现倒着推才能表示出全部方案,即并不是我一旦收集到 n n 个瓶子就停下,而是还可能可有由它自己推到或者经过一番环之后再推到
Q:好啊(我最喜欢记结论了),但是环是什么意思?大佬
A:你没发现具有递推关系的期望dp就是一个图吗?边有边权,上个状态与本步状态之前存在连边,可能一些特殊的图还有环等其他的性质
Q:哦!好像yy出来了,谢谢大佬
A:#@(U)#@E
由上文发现,
经过一波合并同类项并约分后
再将i=i-1代入
由于是倒着推的,现在已知 f[i] f [ i ] ,推的 f[i−1] f [ i − 1 ] ,那么答案不就是
f[n]=0 f [ n ] = 0
这就是答案,真简单
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
inline int read()
{
char ch='!';int z=1,num=0;
while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
if(ch=='-')z=-1,ch=getchar();
while(ch<='9'&&ch>='0')num=(num<<3)+(num<<1)+ch-'0',ch=getchar();
return z*num;
}
ll n;
ll gcd(ll a,ll b)
{
if(!b)return a;
else return gcd(b,a%b);
}
ll js(ll x)
{
ll cnt=0;
while(x)
{
x/=10;
cnt++;
}
return cnt;
}
int main()
{
n=read();
if(n==1){puts("1");return 0;}
if(n==2){puts("3");return 0;}
ll f1=3,f2=2;
for(int i=3;i<=n;++i)
{
ll c=gcd(f2,i);
ll lcm=f2*i/c;
ll d1=lcm/f2,d2=lcm/i;
f1=f1*d1+d2;
c=gcd(f1,lcm);
f1/=c;f2=lcm/c;
}
f1*=n;
ll c=gcd(f1,f2);
f1/=c;f2/=c;
ll k=f1/f2;
ll a1=js(k);
if(!f1)
{
cout<<k<<endl;
}
else
{
ll a2=js(f2);
for(int i=1;i<=a1;++i)
cout<<' ';
cout<<f1%f2<<endl;
if(k>=1)cout<<k;
for(int i=1;i<=a2;++i)
cout<<'-';
cout<<endl;
for(int i=1;i<=a1;++i)
cout<<' ';
cout<<f2<<endl;
}
return 0;
}