题解:P15571 [USACO26FEB] Strange Function B

开发板推荐:天空星STM32F407VET6开发板

超高性价比 STM32主控 | 超高主频 | 一板兼容百芯 | 比赛神器 | 沉金彩色丝印

先考虑全体为 000111 的数。想要最后变为 000 就要抵消掉所有的 111。从小考虑:

111:一次操作变为 000

10101010→−19→翻转1→−1010 \xrightarrow{-1} 9 \xrightarrow{\text{翻转}} 1 \xrightarrow{-1} 01019翻转110

100100100100→−199→翻转11→10→…100 \xrightarrow{-1} 99 \xrightarrow{\text{翻转}} 11 \rightarrow 10 \rightarrow \dots100199翻转1110

可以发现当 10…010\ldots0100111 后变为 9…99\ldots999,通过翻转就变成了 1…11\ldots111

也就是说想抵消第 nnn 位(从右往左)的 111,相当于抵消第 111 到第 n−1n-1n1 位上的 111 再加 222 步。由此得出转移。

dp[1] = 1;
int cnt = 1; // 把第 1 到第 i-1 位上的 1 抵消所耗次数
for (int i = 2; i <= 200004; i++) {
    dp[i] = (cnt + 2) % 1000000007;
    (cnt += dp[i]) %= 1000000007;
}

对于每一次询问,先将非全体为 000111 的数转成 010101,然后用初始化完的数据去累加。

#include <bits/stdc++.h>
using namespace std;
int dp[200004]; // 把第 i 位(从右往左)的 1 抵消所耗次数
int t;
int a[200004];

signed main() {
    dp[1] = 1;
    int cnt = 1; // 把第 1 到第 i-1 位上的 1 抵消所耗次数
    for (int i = 2; i <= 200004; i++) {
        dp[i] = (cnt + 2) % 1000000007;
        (cnt += dp[i]) %= 1000000007;
    }
    cin >> t;
    while (t--) {
        string s;
        cin >> s;
        for (int i = 0; i < s.size(); i++) a[i + 1] = s[i] - '0';
        int n = s.size();
        int ans = 0;
        for (int i = 1; i <= n; i++) {
            if (a[i] != 0 and a[i] != 1) {
                a[i] = a[i] % 2;
                ans = 1; // 先把数字转成 01,花费 1 次
            }
        }
        for (int i = n; i >= 1; i--) { // 从右往左
            (ans += (a[i] ? dp[n - i + 1] : 0)) %= 1000000007;
        }
        cout << ans << "\n";
    }
    return 0;
}

洛谷链接:
https://www.luogu.com.cn/article/9hwxcho3

开发板推荐:天空星STM32F407VET6开发板

超高性价比 STM32主控 | 超高主频 | 一板兼容百芯 | 比赛神器 | 沉金彩色丝印

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值