Problem - D2 - Codeforces [插入计数]

Problem - D2 - Codeforces

trick:相对位置关系 可以插入计数

直接D1 D2一起讲解

先简单看D1 也就是没有问号的时候

那么对w的每个字符 如果是1 就有有一个子数组mex=i

反之就不能有子数组mex=i;

首先对于单个0 以及整个区间的情况 一定会有mex=1 以及mex=n;

因此w1=wn=1;

其次我们计算方案数 [插入计数]

我们可以通过插入0到n-1这些数字来构造一个合法排列

刚开始插入0 当0到k-1已经定了的时候 我们要插入k

若wk=1 那么k能插入的位置只有整个已插入数字的左右两侧 只有这样才能保证有mex=k存在

若wk=0 那么k可以插入到已经插入的相邻数字之间 已经插入了k个数字 那就有k-1个位置可以插入 这样的话当区间选到k的时候 mex不可能为k

也就是wi=1 就乘2 wi=0 就乘i;

由于取模 所以判断ans与c是否整除的时候不能最后除法判断 要在每个乘法的过程 用c/(gcd(c,x))x表示ans的因子 也就是上述乘法过程中的每个数

对于D2部分 ?可以为1 可以为0

我们要保证答案不被c整除并且答案尽可能小

那么非?部分已经确定 我们用c除以固定部分的公因数后得到c1 那么c1与剩下部分的乘积不能整除

想要尽可能小 我们肯定要尽可能选择乘2 而不是乘i

当我们全选择乘2的时候那么乘积就是一个2的次幂 如果c不是二的次幂 完全就可以这么贪心的选择

当c是二的次幂的时候 假设有x个? 那么就是x次幂 假设c是k次幂 我们要尽可能让x<k 这样就不会整除 也就是要选择问号 变为0 乘i 如果i是偶数 那么天然带2 无法降低2的次幂 我们只能选择奇数变成0 偶数必须全变成2 我们选择较小的奇数变为0 这样的话 乘的i尽可能小 答案也小

代码如下:

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

#define int long long

const int mod = 1e9+7;
void solve() {
    int n, c;
    cin >> n >> c;
    string s;
    cin >> s;
    if (s[1] == '?') {
        s[1] = '0';
    }
    if (s[0] == '0' || s[n-1] == '0') {
        cout << -1;
        return;
    }
    s[0] = '1';
    s[n-1] = '1';
    vector<int> good;
    int cnt = 0;
    for (int i = 0; i < n-1; ++i) {
        if (s[i] == '0') {
            c /= gcd(c, i);
        } else if (s[i] == '1') {
            c /= gcd(c, 2ll);
        }else {
            cnt++;
            if (i % 2 == 1) {
                good.push_back(i);
            }
        }
    }
    if (c != (1 << __lg(c))) {
        int ans = 1;
        for (int i = 0; i < n-1; ++i) {
            if (s[i] == '0') {
                ans *= i;
            }else {
                ans *= 2;
            }
            ans %= mod;
        }
        cout << ans;
        return;
    }
    int w = cnt;
    int h = __lg(c);
    for (int i = 0; i < good.size(); ++i) {
        if (w < h) {
            break;
        } else {
            s[good[i]] = '0';
            w--;
        }
    }
    if (w >= h) {
        cout << -1;
        return;
    }
    int ans = 1;
    for (int i = 0; i < n-1; ++i) {
        if (s[i] == '0') {
            ans *= i;
        }else {
            ans *= 2;
        }
        ans %= mod;
    }
    cout << ans;
}

signed main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    int t = 1;
    cin >> t;
    while (t--) {
        solve();
        cout << '\n';
    }
}
相关推荐
programhelp_15 小时前
2026 Fall Coinbase Software Engineer OA 真题分享与通关指南
算法
CQU_JIAKE15 小时前
5.19【A】
算法
数智工坊15 小时前
【FDA论文阅读】: 傅里叶域自适应——零训练成本的语义分割无监督域适配方法
论文阅读·人工智能·学习·算法·自动驾驶
Gauss松鼠会15 小时前
【GaussDB】GaussDB 常见问题及解决方案汇总
java·数据库·算法·性能优化·gaussdb·经验总结
炽烈小老头15 小时前
【 每天学习一点算法 2026/05/19】二叉树中的最大路径和
学习·算法
人道领域16 小时前
【LeetCode刷题日记】106.从遍历序列重建二叉树:手撕递归边界,彻底搞懂左闭右闭 vs 左闭右开
java·算法·leetcode
.魚肉16 小时前
Raft 共识算法 · 演示系统(多终端)
算法·go·raft·分布式系统
念恒1230616 小时前
Python(while循环)
数据结构·python·算法
神奇小汤圆16 小时前
字节面试官:你知道Claude Code的多Agent实现机制吗?
算法
运筹vivo@16 小时前
LeetCode 2540. 最小公共值
算法·leetcode·职场和发展