Codeforces 1452D《Radio Towers》 DP做法

Codeforces 1452D《Radio Towers》题解

原题链接:https://codeforces.com/problemset/problem/1452/D

题目的描述

There are n+2 towns located on a coordinate line, numbered from 0 to n+1. The i-th town is located at the point i.

You build a radio tower in each of the towns 1,2,…,n with probability 1/2 (these events are independent). After that, you want to set the signal power on each tower to some integer from 1 to n (signal powers are not necessarily the same, but also not necessarily different). The signal from a tower located in a town i with signal power p reaches every city c such that |c−i|<p.

After building the towers, you want to choose signal powers in such a way that:

towns 0 and n+1 don’t get any signal from the radio towers;
towns 1,2,…,n get signal from exactly one radio tower each.
For example, if n=5, and you have built the towers in towns 2, 4 and 5, you may set the signal power of the tower in town 2 to 2, and the signal power of the towers in towns 4 and 5 to 1. That way, towns 0 and n+1 don’t get the signal from any tower, towns 1, 2 and 3 get the signal from the tower in town 2, town 4 gets the signal from the tower in town 4, and town 5 gets the signal from the tower in town 5.

Calculate the probability that, after building the towers, you will have a way to set signal powers to meet all constraints.

Input
The first (and only) line of the input contains one integer n (1≤n≤2⋅105).

Output
Print one integer — the probability that there will be a way to set signal powers so that all constraints are met, taken modulo 998244353.

Formally, the probability can be expressed as an irreducible fraction xy. You have to print the value of x⋅y−1mod998244353, where y−1 is an integer such that y⋅y−1mod998244353=1.

Sample Input

2

Sample Output

748683265

Sample Input

3

Sample Output

748683265

Sample Input

5

Sample Output

842268673

Sample Input

200000

Sample Output

202370013

大致题意

嗯...大概就是,1~n的每个位置都可以摆放一盏灯,但摆不摆灯不是你决定的,每个位置各
有1/2的概率会摆,1/2的概率不会摆,但是一旦灯摆下来了,灯能照亮的距离,是你可以
自主决定的,比如,灯能照亮的距离是1,那么他就只能照亮他自己,灯能照亮的距离如果
是2,那么他除了自己以外,还会照亮左边一个和右边一个。0号位和n+1号位不能被
照亮,1~n号位必须被照亮,且每个点只能被一盏灯照亮,不可以被多盏灯照亮,这样
的方案就是合法的,否则非法。题目要求的是合法的概率。

解题思路和方法

直接使用DP来写就好了,由于我喜欢结合代码来讲,所以请看以下完整代码
在代码中我打有相应的注释。

完整代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int mod=998244353;
const int maxn=2e5+10;
ll dp[maxn],odd[maxn],even[maxn];
ll ksm(ll a,ll b)
{
	ll t=1;
	while(b)
	{
		if(b&1) t=t*a%mod;
		a=a*a%mod;
		b>>=1;
	}
	return t;
}
int n,m;
int main()
{
	cin>>n;
	int i,j,k;
	dp[0]=dp[1]=1;
	//状态要如何更新呢?
	//dp[i]表示照亮了1~i的所有地区有多少种情况
	odd[1]=1;//奇数
	even[0]=even[1]=1;  //偶数
	//待会你就会知道为什么存奇数和偶数了  
	
	for(i=2;i<=n;i++)
	{
		dp[i]=(dp[i]+dp[i-1])%mod; //自己亮起了一盏1的小灯的情况
		
		//接下来这个>=3是怎么回事呢
		//你这样想嘛,你至少得有3个没被照亮的地方,你才能够让一盏灯来照亮这个地方
		//就比如,用1表示这个地方已经照亮 ,0表示这个地方还没被照亮
		//那么接下来,假设有五个点,现在是 11000
		//你看,你得在三个0中间的位置放下一盏距离为2的灯,你就可以转换成11111
		//那么这里的状态转移方程就变成了dp[5]+=dp[2] 
		//然后呢,10000能不能用放置一盏灯来变成11111呢?
		//显然不行啊。
		// 因为按题目的东西,你能照亮距离为2的地方,就意味着你必须照亮左边一个格子和右边一个格子
		//如果你要照亮距离为3的地方,那就意味着你必须照亮左边两个格子,右边两个格子,还有中间的你自己
		//所以,只有三个状态能推到11111,他们分别是
		//  00000(在第三个位置放下距离为2的灯)
		// 还有11000 (在第四个位置放下距离为2的灯)
		//以及11110(在第五个位置放下距离为1的灯)
		/*
			那么接下来的就好办了,总状态方程就是
			dp[x]= dp[x-1]+dp[x-3]+dp[x-5]+dp[x-7]....
			那么odd[i]数组和even[i]数组则是分别保存前i个dp值里,下标为奇数的dp的前缀和
																下标为偶数的dp的前缀和 
		*/ 
		if(i>=3)  //先判断-3会不会是负数 
		{
			if(i&1) dp[i]=(dp[i]+even[i-3])%mod;
			else dp[i]=(dp[i]+odd[i-3])%mod;
		} 
		
		//下面更新前缀和 
		odd[i]=odd[i-1];
		even[i]=even[i-1];
		
		if(i&1) odd[i]+=dp[i],odd[i]%=mod;
		else even[i]+=dp[i],even[i]%=mod;
		 
	}
//	cout<<dp[n]<<endl;
	//那么到这里,dp[n]就是我们求得的,照亮1~n的总方案数
	//好你可能会问了,我们求摆放灯的总方案数干什么?
	//宁不是要求总概率吗? 
	//然而你想想,每盏灯都有1/2的概率亮,1/2的概率不亮
	//那么总摆放灯的可能性有多少种?
	//每个位置都有等概率两种选择,放或者不放
	//那总摆放灯的可能性就是2*2*2*2......总共2的n次方种嘛
	//对啊,那概率就是dp[n]/ 2的n次方
	// 下面我们求一下分母 
	ll mom=1;
	for(i=1;i<=n;i++)
		mom=mom*2%mod;
	//求好啦 
	//然后逆一下元,取一下模,就结束了 
	ll ans=ksm(mom,mod-2)%mod*dp[n]%mod;
	cout<<ans<<endl;
	//耶。 
	return 0;
}

一点点想说的话

不写博客很久很久了,也就刚学算法的时候开始写了点东西(懒是原罪)
然后今天突然诈尸主要是因为学长今天扔了这道DP给我,巧的是我写完之后,一个朋友
刚好来问我这道题,于是绞尽脑汁打了注释想了想怎么教人,写了一堆注释之后,想了想
要不然直接发博客上好了,于是事情就变成这个样子了.jpg
刚好最近写题都比较喜欢在打代码的过程中写注释了,所以以后可能会不定时写写博客了
当作笔记也好,或者能教教人也好。
嗯,以上。然后就......
希望这篇微不足道的博客能对你有所帮助.jpg
区间DP是一种动态规划的方法,用于解决区间范围内的问题。在Codeforces竞赛中,区间DP经常被用于解决一些复杂的字符串或序列相关的问题。 在区间DP中,dp[i][j]表示第一个序列前i个元素和第二个序列前j个元素的最优解。具体的转移方程会根据具体的问题而变化,但是通常会涉及到比较两个序列的元素是否相等,然后根据不同的情况进行状态转移。 对于区间长度为1的情况,可以先进行初始化,然后再通过枚举区间长度和区间左端点,计算出dp[i][j]的值。 以下是一个示例代码,展示了如何使用区间DP来解决一个字符串匹配的问题: #include <cstdio> #include <cstring> #include <string> #include <iostream> #include <algorithm> using namespace std; const int maxn=510; const int inf=0x3f3f3f3f; int n,dp[maxn][maxn]; char s[maxn]; int main() { scanf("%d", &n); scanf("%s", s + 1); for(int i = 1; i <= n; i++) dp[i][i] = 1; for(int i = 1; i <= n; i++) { if(s[i] == s[i - 1]) dp[i][i - 1] = 1; else dp[i][i - 1] = 2; } for(int len = 3; len <= n; len++) { int r; for(int l = 1; l + len - 1 <= n; l++) { r = l + len - 1; dp[l][r] = inf; if(s[l] == s[r]) dp[l][r] = min(dp[l + 1][r], dp[l][r - 1]); else { for(int k = l; k <= r; k++) { dp[l][r] = min(dp[l][r], dp[l][k] + dp[k + 1][r]); } } } } printf("%d\n", dp[n]); return 0; } 希望这个例子能帮助你理解区间DP的基本思想和应用方法。如果你还有其他问题,请随时提问。
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值