Codeforces757D Felicity's Big Secret Revealed

本文介绍了一种计算特定二进制字符串的有效切割方案数量的方法。通过动态规划算法,利用状态压缩技术来解决这一问题。文章提供了完整的代码实现,并解释了算法背后的逻辑。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

真·失踪人口回归。

我来证明我没有退役。

Description

给定一个长度为 \(n(n\le 75)\)\(01\) 串。将 \(01\) 串用 \(m\) 条竖线划分为 \(m + 1\) 个部分,将两条竖线之间的 \(01\) 串转为十进制数。若这些数的最大值为 \(MAX\) 且取值范围为 \([1,MAX]\) 且包括了 \([1,MAX]\) 中的所有数,则为一次有效的 \(m\) 切割。定义 \(m\) 切割的方案数为 \(f(m)\) 。求 \[\sum_{k=2}^{n+1}f(k)\]

Solution

因为 \(1\)\(20\) 的二进制长度相加正好为 \(74\) ,故 \(MAX\) 最大为 \(20\)

考虑状压。\(dp[i][j]\) 表示在 \(i-1\)\(i\) 之间有一条竖线,在之前的划分中出现的数的集合为 \(j\) 的方案数。

转移见代码。

#include<bits/stdc++.h>
using namespace std;

#define N 100
#define rep(i, a, b) for (int i = a; i <= b; i++)

const int P = 1e9+7;
int n, num[N][N], dp[N][(1 << 20) + 5];
char s[N];

int main() {
    scanf("%d%s", &n, s + 1);
    rep(i, 1, n) { int k = 0; rep(j, i, n) if ((k = (k << 1) + s[j] - '0') > 20) break; else num[i][j] = k; }
    rep(i, 1, n) {
        dp[i][0] = 1;
        rep(j, 0, (1 << 20) - 1) if (dp[i][j]) rep(k, i, n) if (num[i][k]) (dp[k + 1][j | (1 << num[i][k] - 1)] += dp[i][j]) %= P;
    }
    int ans = 0; rep(i, 1, n + 1) rep(j, 1, 20) (ans += dp[i][(1 << j) - 1]) %= P;
    cout << ans;
    return 0;
}

转载于:https://www.cnblogs.com/aziint/p/9098038.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值