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;
}
posted @ 2026-06-15 17:13  kzssCCC  阅读(8)  评论(0)    收藏  举报