CF2189D2 思路分享(数论)
https://codeforces.com/problemset/problem/2189/D2
题意概述
对于一个 \(01\) 串 \(w_1w_2\cdots w_n\),定义 \(f(w)\) 为:
-
\(p\) 是 \([0,1,\cdots,n-1]\) 的一个排列.
-
对于每个 \(i\),若 \(w_i\) 为 \(1\),则存在 \(p\) 的某个子串的 \(mex\) 为 \(i\),若 \(w_i\) 为 \(0\),则不存在这样的子串.
-
符合条件的 \(p\) 数量.
给定 \(01\) 串 \(s\) 和整数 \(c\),\(s\) 中有些位置为 \(?\) 表示可以自选,求满足 \(f(s)\) 在不是 \(c\) 的倍数的情况下的最小值,模 \(10^9+7\),不存在输出 \(-1\).
\(3\le n \le 2\cdot 10^5\),\(1\le c \le 10^9\).
思路
对于没有 \(?\) 的 \(s\),若 \(s_1=0\) 或 \(s_n=0\),则 \(f(s)=0\).
若 \(s_i=1\) ,放在两边,贡献 \(2\);否则,放在中间,贡献 \(i-1\).
不考虑限制,想要 \(f(s)\) 最小,让 \(i\ge 3\) 时 \(s_i=1\),\(s_2\) 取 \(0\).
在这基础上调整,将某个位置 \(s_i\) 从 \(1\) 改成 \(0\).
-
若 \(i\) 是奇数,在附带 \(2\) 的因子的基础上又新增因子,没有意义;
-
若 \(i\) 是偶数,删掉了一个 \(2\) 的因子,新增了一个因子.
发现只能减少 \(2\) 的因子数量.
统计可调整的位置数量 \(m\),当前 \(s\) 所有贡献的因子 \(2\) 数量 \(ts\),\(c\) 的因子 \(2\) 数量 \(tc\).
若 \(f(s)\) 已经不是 \(c\) 的倍数,不需要调整,判断方法如下:
对于 \(c\) 和 \(s\) 的所有贡献,都除掉 \(2\) 的因子部分,记 \(s\) 某个贡献处理后为 \(v\),每次让 \(c\) 除掉 \(\gcd(c,v)\).
如果 \(c\) 最终不为 \(1\),或者 \(ts \lt tc\),已经不是倍数了.
如果当前是倍数,贪心地选前 \(ts-tc+1\) 个改成 \(0\) 即可,不够输出 \(-1\).
时间复杂度 \(\mathcal{O}(n)\).
代码
//author:kzssCCC
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int MOD = 1e9+7;
void solve(){
int n,c;
cin >> n >> c;
string s;
cin >> s;
s = ' '+s;
if (s[1]=='0' || s[n]=='0'){
cout << -1 << '\n';
return;
}
s[1] = s[n] = '1';
int tc = __builtin_ctz(c);
c /= 1<<tc;
vector<int> wait;
for (int i=2;i<n;i++){
if (s[i]!='?') continue;
if (i==2){
s[i] = '0';
}
else{
s[i] = '1';
if (i%2==0){
wait.push_back(i);
}
}
}
int m = wait.size();
int ts = 0;
for (int i=2;i<=n;i++){
if (s[i]=='0'){
int v = i-1;
int temp = __builtin_ctz(v);
ts += temp;
v /= 1<<temp;
c /= __gcd(c,v);
}
else{
ts++;
}
}
auto cal = [&](){
ll res = 1;
for (int i=2;i<=n;i++){
if (s[i]=='0'){
res = res*(i-1)%MOD;
}
else{
res = res*2%MOD;
}
}
return res;
};
if (c!=1 || ts<tc){
cout << cal() << '\n';
return;
}
if (ts-m>=tc){
cout << -1 << '\n';
return;
}
int need = ts-tc+1;
for (int i=0;i<need;i++){
s[wait[i]] = '0';
}
cout << cal() << '\n';
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
int t = 1;
cin >> t;
while (t--) solve();
return 0;
}

浙公网安备 33010602011771号