DP练习题回顾

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

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


P5104 红包发红包

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

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

就开始了漫长的证明旅途

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

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

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

(~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~)(a/bequiv x(mod~p))

(~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Rightarrow a imes 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
",ans);
	}
	return 0;
}
原文地址:https://www.cnblogs.com/jkzcr01-QAQ/p/13575216.html