CodeForces 1452 D - Radio Towers
题目大意:
有 n n n 个灯塔,每个灯塔有 1 / 2 1/2 1/2 的概率设一个信号发射器,覆盖长度可以自己设置 x x x, 要求 所有灯塔都要有信号,并且每个灯塔只能被一个信号覆盖,并且不能覆盖到 0 0 0 和 n + 1 n+1 n+1。
思路:
设置 d p [ i ] dp[i] dp[i] 表示第 i i i 个灯塔刚好被覆盖的方案数,答案就是 d p [ n ] / 2 n dp[n] / 2^n dp[n]/2n,所以先求 d p [ n ] dp[n] dp[n] 即可
首先 d p [ i ] = d p [ i − 1 ] dp[i] = dp[i-1] dp[i]=dp[i−1], 因为可以选择覆盖自己,即刚好从前面转移过来,然后就可以尝试覆盖别人即: d p [ i ] + = d p [ i − 2 ∗ k − 1 ] , k > = 1 dp[i] += dp[i-2*k-1] , k >= 1 dp[i]+=dp[i−2∗k−1],k>=1,这肯定是要判断边界的。这是什么意思呢,仔细观察这个,比如 d p [ 3 ] dp[3] dp[3] 就可以让 i = 2 i=2 i=2 覆盖 [ 1 − 3 ] [1-3] [1−3], 那么就可以从 d p [ 0 ] dp[0] dp[0] 转移过来,依次类推。
这里可以用奇偶前缀和数组优化,就可以过.
然后可以再扩展下这个公式:
首先 d p [ 0 ] = d p [ 1 ] = d p [ 2 ] = 1 dp[0] = dp[1] = dp[2] = 1 dp[0]=dp[1]=dp[2]=1,
据一些例子 d p [ 3 ] = d p [ 2 ] + d p [ 0 ] dp[3] = dp[2] + dp[0] dp[3]=dp[2]+dp[0], 但是 d p [ 0 ] = d p [ 1 ] dp[0] = dp[1] dp[0]=dp[1], 所以可以写成 d p [ 3 ] = d p [ 2 ] + d p [ 1 ] dp[3] = dp[2] + dp[1] dp[3]=dp[2]+dp[1]
d p [ 5 ] = d p [ 4 ] + d p [ 2 ] + d p [ 0 ] = d p [ 4 ] + d p [ 2 ] + d p [ 1 ] = d p [ 4 ] + d p [ 3 ] dp[5] = dp[4] + dp[2] + dp[0] = dp[4] + dp[2] + dp[1] = dp[4] + dp[3] dp[5]=dp[4]+dp[2]+dp[0]=dp[4]+dp[2]+dp[1]=dp[4]+dp[3]
d p [ 7 ] = d p [ 6 ] + d p [ 4 ] + d p [ 2 ] + d p [ 0 ] = d p [ 6 ] + d p [ 5 ] dp[7] = dp[6] + dp[4] + dp[2] + dp[0] = dp[6] + dp[5] dp[7]=dp[6]+dp[4]+dp[2]+dp[0]=dp[6]+dp[5]
d p [ 4 ] = d p [ 3 ] + d p [ 1 ] = d p [ 3 ] + d p [ 2 ] dp[4] = dp[3] + dp[1] = dp[3] + dp[2] dp[4]=dp[3]+dp[1]=dp[3]+dp[2]
d p [ 6 ] = d p [ 5 ] + d p [ 3 ] + d p [ 1 ] = d p [ 5 ] + d p [ 3 ] + d p [ 2 ] = d p [ 5 ] + d p [ 4 ] dp[6] = dp[5] + dp[3] + dp[1] = dp[5] + dp[3] + dp[2] = dp[5] + dp[4] dp[6]=dp[5]+dp[3]+dp[1]=dp[5]+dp[3]+dp[2]=dp[5]+dp[4]
看到这里,应该可以找出规律,刚好就是经典的 F i b Fib Fib 数列
证明也不难,分奇偶数讨论
dp代码
#include <bits/stdc++.h>
using namespace std;
#define me(a, b) memset(a, b, sizeof(a))
#define IOS() ios::sync_with_stdio(false), cin.tie(0)
#define endl '\n'
typedef long long ll;
typedef pair<ll, ll> pll;
typedef pair<int, int> pii;
const int INF = 0x3f3f3f3f;
const int maxn = 2e5 + 5;
const ll mod = 998244353;
ll mypow(ll a, ll b)
{
ll res = 1;
while(b) {
if(b&1) res = res * a % mod;
a = a * a % mod;
b >>= 1;
}
return res;
}
ll dp[maxn];
ll odd[maxn], even[maxn];
int main()
{
IOS();
int n;
cin >> n;
dp[0] = dp[1] = dp[2] = 1;
odd[0] = 0;
even[0] = odd[1] = odd[2] = 1;
even[2] = 2;
for(int i = 3; i <= n; ++i) {
dp[i] = dp[i-1];
if(i&1)
dp[i] += even[i-3];
else
dp[i] += odd[i-3];
dp[i] %= mod;
odd[i] = odd[i-1];
even[i] = even[i-1];
if(i&1)
odd[i] = (odd[i] + dp[i]) % mod;
else
even[i] = (even[i] + dp[i]) % mod;
}
// cout << dp[n] << endl;
ll ans = dp[n] % mod * mypow(mypow(2, n), mod-2) % mod;
cout << ans << endl;
return 0;
}
Fib代码
#include <bits/stdc++.h>
using namespace std;
#define me(a, b) memset(a, b, sizeof(a))
#define IOS() ios::sync_with_stdio(false), cin.tie(0)
#define endl '\n'
typedef long long ll;
typedef pair<ll, ll> pll;
typedef pair<int, int> pii;
const int INF = 0x3f3f3f3f;
const int maxn = 2e5 + 5;
const ll mod = 998244353;
ll mypow(ll a, ll b)
{
ll res = 1;
while(b) {
if(b&1) res = res * a % mod;
a = a * a % mod;
b >>= 1;
}
return res;
}
ll fib[maxn];
int main()
{
IOS();
int n;
cin >> n;
fib[1] = fib[2] = 1;
for(int i = 3; i <= n; ++i)
fib[i] = (fib[i-2] + fib[i-1]) % mod;
ll ans = fib[n] * mypow(mypow(2, n), mod-2) % mod;
cout << ans << endl;
return 0;
}
总结:
很有意思的题目