DP练习题回顾

同机房好友发了一个题单,然后。。本蒟蒻又来练DP啦!(被绿题狂虐中

今天继续讲题,又没学啥。。


P5104 红包发红包

拿到这题目,第一眼就发现,每次取的期望不是取一半吗?

然后瞄一眼样例,咦!好像我是对的!

就开始了漫长的证明旅途

嗯很好,我不会,可以转题解。。。

既然不会,就按着我的思路上代码吧!

等等,分数取模!!蒟蒻的我听都没听说过。。还是得靠度娘:

\(~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\)\(a/b\equiv x(mod~p)\)

\(~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ \Rightarrow a\times b^{-1}\equiv x(mod~p)\)

\(b^{-1}\)是啥?不就是\(b\)的逆元吗?

OK,所以答案就是分子乘以分母的逆元

手起,码落!

#include<bits/stdc++.h>
#define re register
#define mod 1000000007
using namespace std;
inline long long Pow(long long x,long long y)
{
	re long long sum=1;
	for(;y;x=(x*x)%mod,y>>=1)
		if(y&1)sum=(sum*x)%mod;
	return sum%mod;
}
long long w,n,k;
int main()
{
	scanf("%lld%lld%lld",&w,&n,&k);
	printf("%lld",w*Pow(Pow(2,k),mod-2)%mod);
	return 0;
}

P6154 游走

一句话题意: 求一个有向无环图的路径长度期望。

这题就是图论期望DP的入门题了,答案就是路径总长除以路径条数,所以设\(f[u]\)表示从\(u\)出发的路径总长,\(g[u]\)表示从\(u\)出发的路径条数,所以\(ans=\frac{\sum_{i=1}^{n}f[i]}{\sum_{i=1}^{n}g[i]}\)。(注意:不走也是一条路径,即路径条数\(+1\),而路径总长不加

状态定义好了,转移方程就简单了:

\[g[u]=1+\sum_{ver[u][v]==1}g[v] \]

\[f[u]=\sum_{ver[u][v]==1}f[v]+g[v] \]

最后的分数取模与上题一样,所以不再赘述。

讲完了,手起,码落:

#include<bits/stdc++.h>
#define re register
#define mod 998244353
using namespace std;
const int M=700005,N=100005;
struct egde{int v,net;}e[M];
inline long long Pow(long long x,long long y)
{
	re long long sum=1;
	for(;y;y>>=1,x=x*x%mod)
		if(y&1)sum=sum*x%mod;
	return sum;
}
long long f[N],g[N];
int n,m,cnt,hd[N];
inline void add(int u,int v){e[++cnt].v=v,e[cnt].net=hd[u],hd[u]=cnt;}
void dfs(int u)
{
	g[u]=1;
	for(re int v,i=hd[u];i;i=e[i].net)
	{
		v=e[i].v;
		if(g[v]==0)dfs(v);
		g[u]=(g[u]+g[v])%mod;
		f[u]=(f[u]+f[v]+g[v])%mod;
	}
}
int main()
{
	scanf("%d%d",&n,&m);
	for(re int i=1,u,v;i<=m;i++)
	{
		scanf("%d%d",&u,&v);
		add(u,v);
	}
	for(re int i=1;i<=n;i++)
		if(g[i]==0)dfs(i);
	for(re int i=1;i<=n;i++)f[0]=(f[0]+f[i])%mod,g[0]=(g[0]+g[i])%mod;
	printf("%lld",f[0]*Pow(g[0],mod-2)%mod);
	return 0;
}

SP1026 FAVDICE - Favorite Dice

一句话题意:一个\(n\)面的骰子,求期望掷几次能使得每一面都被掷到。(题目本就这一句话

第一眼看过去,擦,这么简单,期望不就是\(n\)吗?

然后我看着样例输出陷入了沉思。。

还是端正推柿子吧:

第一次取:有\(\frac{n}{n}\)的机会取到没取过的点

由于已经取了一个,所以第二次:有\(\frac{n-1}{n}\)的机会取到没取过的点,也就是要取\(\frac{n}{n-1}\)次。

同理,第三次:有\(\frac{n-2}{n}\)的机会取到没取过的点,要取\(\frac{n}{n-2}\)次。

......

\(n\)次:有\(\frac{n-n+1}{n}\)的机会取到没取过的点,要取\(n\)次。

综上所述,\(ans=\sum_{i=1}^{n}\frac{n}{i}\)

SO?手起,码落:

#include<bits/stdc++.h>
#define re register
using namespace std;
int T,n,p;
double ans;
int main()
{
	scanf("%d",&T);
	for(;T--;)
	{
		ans=0;
		scanf("%d",&n);
		for(re int i=1;i<=n;i++)ans+=n*1.0/i;
		printf("%.2lf\n",ans);
	}
	return 0;
}
posted @ 2020-08-28 08:16  Chester1011  阅读(133)  评论(0编辑  收藏  举报
/*simplememory*/