# CF1684H Hard Cut 题解

Table of Contents

何 ∗3400*3400?

洛谷传送门

CF 传送门

题意

给定 0101 串 ss,要求将 ss 划分为若干区间,使得每段区间视为二进制数的和为 22 的幂次。

思路

设 ss 中 11 的数量为 cntcnt,cnt=0cnt=0 显然无解。

设最后的和为 2d2^d,手玩可以发现 dd 若是 O(n)O(n) 级别则很难有解,但 2d2^d 是 O(n)O(n) 级别则几乎有解,于是可以假定 dd 是 O(log⁡n)O(\log n) 级别的。

一个直觉是 2d2^d 与 cntcnt 越接近越容易有解,因为这意味着每个区间的长度都不长,从而能划分出更多的区间,调整空间也更大。

考虑从小到大枚举 dd 并判断能否取到,首先能取到显然 2d≥cnt2^d\ge cnt。

于是可以想到以下贪心:设当前已经划分的总和为 sumsum,每次选择最长的前缀(设其代表的二进制数为 vv)满足 sum+v+去除该前缀后 1 的个数≤2dsum+v+\text{去除该前缀后 1 的个数}\le 2^d。取最长前缀的目的是使后面需要的总和与 11 的个数差距最小。

发现没什么反例,交一发就过了。

事实上对于绝大多数 ss,只需考虑最小的 dd 满足 2d≥cnt2^d\ge cnt 即能构造出方案,详见下面的证明。

代码

#include <bits/stdc++.h>
using namespace std;
int n,c;
string s;
bool check(int d){
if(d<c) return 0;
vector<pair<int,int> >res;
int cnt=c;
for(int i=1,j,v;i<=n;i=j+1){
j=i-1,v=0;
while(j<n&&v*2+cnt<=d) j++,v=v*2+s[j]-'0',cnt-=s[j]-'0';
res.emplace_back(i,j),d-=v;
}
if(d) return 0;
cout<<res.size()<<"\n";
for(auto [l,r]:res) cout<<l<<" "<<r<<"\n";
return 1;
}
void solve(){
cin>>s,n=s.length(),s=" "+s,c=0;
for(int i=1;i<=n;i++) c+=s[i]-'0';
if(!c){cout<<"-1\n";return;}
for(int d=1;!check(d);d<<=1);
}
int main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int Ca;cin>>Ca;while(Ca--)solve();
return 0;
}

证明 by ChatGPT

设 m=cnt⁡1(s)m=\operatorname{cnt}_1(s)。若 m=0m=0,所有段的值都为 00,显然无解。下设 m>0m>0。

固定目标 T=2d≥mT=2^d\ge m。贪心每次取最长前缀 vv,满足

sum+v+sufcnt1≤T.\text{sum}+v+\text{sufcnt1}\le T.

这里把剩余字符全部单独切开时,它们的和恰好是 sufcnt1sufcnt1,因此该条件表示:当前切法仍有可能不超过 TT。

下面证明从最小的 2d≥m2^d\ge m 开始枚举一定能成功。

1. 贪心失败时的必要条件

假设目标 TT 时贪心最终切出了若干段。对第 ii 段记

vi=该段二进制值,ci=该段中 1 的个数,v_i=\text{该段二进制值},\qquad c_i=\text{该段中 }1\text{ 的个数},

并定义

ei=vi−ci.e_i=v_i-c_i.

eie_i 就是相比于把这一段全部拆成单字符后,多出来的贡献。

假设最后没有达到 TT,而是还差

δ=T−∑ivi>0.\delta=T-\sum_i v_i>0.

令

E=T−m.E=T-m.

显然

∑iei=∑ivi−m=E−δ.(1)\sum_i e_i =\sum_i v_i-m =E-\delta. \tag{1}

考虑任意一个非最后段。由于贪心已经取了最长合法前缀,若再把下一位 bb 接进来,该段的值变为 2vi+b2v_i+b,而后缀的 11 数减少 bb,所以必有

pre+2vi+∑j>icj>T.\text{pre}+2v_i+\sum_{j>i}c_j>T.

另一方面最终总和为 T−δT-\delta,即

pre+vi+∑j>ivj=T−δ.\text{pre}+v_i+\sum_{j>i}v_j=T-\delta.

两式相减得到

vi>δ+∑j>iej.(2)\boxed{v_i>\delta+\sum_{j>i}e_j}. \tag{2}

这是核心不等式。

一个含 cic_i 个 11 的二进制数至少为 2ci−12^{c_i}-1,故

ei=vi−ci≥2ci−1−ci.e_i=v_i-c_i\ge 2^{c_i}-1-c_i.

于是

ci−ei≤1.c_i-e_i\le1.

而 ci−ei>0c_i-e_i>0 时只能有两种情况:

(ci,ei,vi)=(1,0,1)(c_i,e_i,v_i)=(1,0,1)

或

(ci,ei,vi)=(2,1,3).(c_i,e_i,v_i)=(2,1,3).

由 (2),vi=1v_i=1 不可能出现在非最后段,所以至多出现一次。

同时 vi=3v_i=3 至多出现两次:若出现三个,取最左边那个,则它右边至少还有两个 e=1e=1,由 δ≥1\delta\ge1,

3>δ+∑j>iej≥3,3>\delta+\sum_{j>i}e_j\ge3,

矛盾。

因此

∑i(ci−ei)≤3.\sum_i(c_i-e_i)\le3.

结合 (1) 得

m−(E−δ)≤3,m-(E-\delta)\le3,

即

m≤E+3−δ≤E+2.(3)\boxed{m\le E+3-\delta\le E+2}. \tag{3}

所以,若目标 TT 贪心失败,则必有 m≤T−m+2m\le T-m+2。

2. 最小的二次幂几乎一定成功

令 PP 为最小的满足

P≥mP\ge m

的 22 的幂。

若 P=mP=m,把所有字符单独切开时总和已经是 PP,贪心显然成功。

下面设 P>mP>m,并令

E=P−m.E=P-m.

由于 PP 是最小的二次幂,

P2<m,\frac P2<m,

因此

m−E=2m−P≥2,m-E=2m-P\ge2,

即

m≥E+2.(4)m\ge E+2. \tag{4}

若贪心失败,由 (3) 又有

m≤E+2.m\le E+2.

故只能全部取等:

m=E+2,δ=1,∑i(ci−ei)=3.m=E+2,\qquad \delta=1,\qquad \sum_i(c_i-e_i)=3.

因此必须恰好出现两个 vi=3v_i=3 和一个最后的 vi=1v_i=1。

还需说明不存在额外的段。若某额外段满足 ci−ei=0c_i-e_i=0,则 ei=cie_i=c_i,即 vi=2civ_i=2c_i。由

ci=ei≥2ci−1−cic_i=e_i\ge2^{c_i}-1-c_i

可知 ci≤2c_i\le2。ci=2c_i=2 时要求 vi=4v_i=4,但 4=(100)24=(100)_2 只有一个 11,不可能;所以只有 ci=1,vi=2c_i=1,v_i=2(或全零段)。

全零非最后段直接违反 (2)。而 vi=2v_i=2 无论放在哪里也不可能:若它右边还有一个 v=3v=3,则由 (2)

2>δ+1=22>\delta+1=2

矛盾;若它在两个 v=3v=3 之后,则最左边的 v=3v=3 右侧已有 e=1+1e=1+1,同样与 (2) 矛盾。

所以失败时切法只能是

3, 3, 1.\boxed{3,\ 3,\ 1}.

因此

m=2+2+1=5,P=8.m=2+2+1=5, \qquad P=8.

也就是说:

最小的 P≥m 只有在 m=5, P=8 时可能失败。\boxed{\text{最小的 }P\ge m\text{ 只有在 }m=5,\ P=8\text{ 时可能失败。}}

3. m=5m=5 时再试 1616 一定成功

若 T=8T=8 失败,上面已经证明贪心切出的值只能是

3,3,1.3,3,1.

所以原串必形如

0a11 0b11 0c1.0^a11\,0^b11\,0^c1.

现在令目标为 1616。

若 b=0b=0,贪心得到

15+1=16.15+1=16.

若 b=1b=1,第一段取到 1101,值为 1313,剩余部分恰好能贡献 33,故

13+3=16.13+3=16.

若 b≥2b\ge2,第一段取到 1100,值为 1212,剩余部分恰好能贡献

3+1=4,3+1=4,

故

12+3+1=16.12+3+1=16.

因此 88 失败时,1616 必定成功。

综上,除全零串外一定有解;按从小到大的顺序枚举 2d≥cnt⁡1(s)2^d\ge\operatorname{cnt}_1(s),上述贪心一定找到答案。事实上,除了 m=5m=5 这一种情况外,第一个二次幂就会成功;m=5m=5 时至多再尝试一次 1616。