1 条题解
-
0
自动搬运
来自洛谷,原作者为

Alex_Wei
**搬运于
2025-08-24 22:18:36,当前版本为作者最后更新于2020-02-06 22:37:17,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
Upd on 2020.10.7 修改一个小 typo。
Subtask :没啥好说的,记得开 long long。
- 接下来的前置知识:有理数取模 P2613。
Subtask :我们设问号的个数为 ,明显可以 暴力枚举问号是 ,计算出符合条件的情况数 ,答案就是 ,对 取模就行了。
时间复杂度:上界为 。
- 接下来我们只讨论如何得到符合条件的情况数,前置知识:基础 DP。
Subtask :考虑 维 DP, 表示前 位同学组成了 个 , 个 ,且当前位为 ( 时为 , 时为 )共有多少种情况,其中 。转移方程:
$$f_{i,j,k,0}=\begin{cases}0&s_i=\texttt{B}\\f_{i-1,j,k-1,1}&s_{i-1}=\texttt{B},s_i=\texttt{G}\\f_{i-1,j,k,0}&s_{i-1}=\texttt{G},s_i=\texttt{G}\\f_{i-1,j,k-1,1}+f_{i-1,j,k,0}&s_{i-1}=\texttt{?}\ ,s_i=\texttt{G}\end{cases} $$的转移方程和上面类似,不再赘述。
最后枚举所有 ,如果 ,情况数就加上 。
时间复杂度:。
- 下文中,我们设 为 的个数, 为 的个数。
Subtask :其实这个 Subtask 是引导你走向正解的(逃
该 Subtask 就是在求最后的 共有多少种情况。
这就不由地让我们提出一个问题: 与 到底有什么关系?它们的差的范围是多少?
如果你想到这个问题,那么恭喜你,你离 AC 本题不远了!
现在的你只需要挖掘出这个性质:在任何时刻,。
应该挺好理解的吧 qwq,举个例子:如果现在有一个转折点 ,那么下一个转折点一定不可能是 ,因为中间一定经过一个 的转折。说的再通俗一点,就是 的省略号中一定有 的转折。
所以这就引出了 Subtask 的解法:仍然是 维 DP, 表示前 位同学, 的值为 , 的值为 ,且当前位为 ( 的定义上文有说明)共有多少种情况,其中 。
这样,时间复杂度就被我们压缩成了 。
注意到空间只有 ,滚动数组优化一下即可。
感谢验题人 Isaunoya 倾情赞助的 std,因为出题人写的 std 锅掉了。
// powered by c++11 // by Isaunoya #include<bits/stdc++.h> using namespace std; const int mod = 1e9 + 7 ; int qpow(int x , int y) { int res = 1 ; for( ; y ; y >>= 1 , x = 1ll * x * x % mod) if(y & 1) res = 1ll * res * x % mod ; return res ; } int inv(int x) { return qpow(x , mod - 2) ; } int n , a , b ; long long m ; const int maxn = 2020 + 0202 ; int arr[maxn] ; int dp[2][maxn][3][2] ; // i // j * a // -(j-k+1) void del(int & x) { if(x >= mod) x -= mod ; } void addGB(int i) { int p = i & 1; for(int j = 0 ; j < i ; j ++) for(int k = 0 ; k < 2 ; k ++) { dp[p][j][k][0] += dp[p ^ 1][j][k + 1][1] ; del(dp[p][j][k][0]) ; } } void addBG(int i) { int p = i & 1; for(int j = 1 ; j < i ; j ++) for(int k = 1 ; k < 3 ; k ++) { dp[p][j][k][1] += dp[p ^ 1][j - 1][k - 1][0] ; del(dp[p][j][k][1]) ; } } void addBB(int i) { int p = i & 1; for(int j = 0 ; j < i ; j ++) for(int k = 0 ; k < 3 ; k ++) { dp[p][j][k][1] += dp[p ^ 1][j][k][1] ; del(dp[p][j][k][1]) ; } } void addGG(int i) { int p = i & 1; for(int j = 0 ; j < i ; j ++) for(int k = 0 ; k < 3 ; k ++) { dp[p][j][k][0] += dp[p ^ 1][j][k][0] ; del(dp[p][j][k][0]) ; } } int main() { // code begin. cin >> n >> m >> a >> b ; for(int i = 1 ; i <= n ; i ++) { char c ; cin >> c ; if(c == '?') arr[i] = 2 ; if(c == 'B') arr[i] = 1 ; if(c == 'G') arr[i] = 0 ; } if(arr[1] < 2) dp[1][0][1][arr[1]] = 1 ; else dp[1][0][1][1] = dp[1][0][1][0] = 1 ; for(int i = 2 ; i <= n ; i ++) { for(int j = 0 ; j < i ; j ++) for(int k = 0 ; k < 3 ; k ++) dp[i & 1][j][k][0] = dp[i & 1][j][k][1] = 0; // 0 - G if(arr[i] == 0 && arr[i - 1] == 0) addGG(i) ; if(arr[i] == 0 && arr[i - 1] == 1) addGB(i) ; if(arr[i] == 0 && arr[i - 1] == 2) addGG(i) , addGB(i) ; // 1 - B if(arr[i] == 1 && arr[i - 1] == 0) addBG(i) ; if(arr[i] == 1 && arr[i - 1] == 1) addBB(i) ; if(arr[i] == 1 && arr[i - 1] == 2) addBB(i) , addBG(i) ; // 2 - ? if(arr[i] == 2 && arr[i - 1] == 0) addGG(i) , addBG(i) ; // ?G if(arr[i] == 2 && arr[i - 1] == 1) addBB(i) , addGB(i) ; // ?B if(arr[i] == 2 && arr[i - 1] == 2) { // ?? addBG(i) , addBB(i) ; addGB(i) , addGG(i) ; } } int cnt = 0 ; for(int i = 1 ; i <= n ; i ++) if(arr[i] == 2) ++ cnt ; int ans = 0 ; for(int j = 0 ; j <= n ; j ++) for(int k = 0 ; k < 3 ; k ++) { if(1ll * j * a - 1ll * (j - k + 1) * b >= m) { ans += dp[n & 1][j][k][0] ; del(ans) ; ans += dp[n & 1][j][k][1] ; del(ans) ; } } cout << 1ll * ans * inv(qpow(2 , cnt)) % mod << '\n' ; return 0 ; // code end. }
- 1
信息
- ID
- 4755
- 时间
- 1000ms
- 内存
- 8MiB
- 难度
- 5
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者