题解:CF2157F Git Gud

· · 题解

令操作次数 M = 10^6, 则 1000=\sqrt{M}N=\frac{M}{4}。后续会用这些分析次数。

1.5\times 10^6 做法

假设没有 +1000 的代价,那么很自然会想到从小到大枚举 y 并将 l 设为 1,次数 N

进一步,看到 \sqrt{M}=1000 自然会联想到根号分块做法。我们不妨每 B 个数字分成一个块,然后对于每个块所代表的区间 [kB+1,(k+1)B],让它们都变成 (k+1)B。这里,可以用类似前文所提到的操作,有一点不一样的是你要把从后往前的每一块一起做。这一步的操作次数是 N+B\sqrt{M}。这一步操作我们称之为“基本操作”。

此时,我们剩下了 B, 2B, \ldots, N\frac{N}{B} 个数字。再用一次前文所提到的操作。这一步的操作次数是 N+\frac{N\sqrt{M}}{B}。我们称之为“最终操作”。

## $O($能过$)$ 做法 只分一次块根本过不了,那我们是否可以多次分块呢? 分块时先分成长度为 $K$ 的块执行一次基本操作,再把剩下的 $\frac{N}{K}$ 个数字分成长 $B$ 的块执行一次,最后执行一次最终操作。操作次数为 $N+K\sqrt{M}+N+B\sqrt{M}+N+\frac{N\sqrt{M}}{KB}$。 化一下式子,$3N+(B+K+\frac{N}{BK})\sqrt{M} \geq 3N+3\sqrt[3]{N}\sqrt{M}$ 当且仅当 $B=K=\sqrt[3]{N}$。可以通过此题。 ## 代码 ```cpp #include<bits/stdc++.h> using namespace std; int n,B; basic_string<pair<int,int> >ans; void out(){ cout<<ans.size()<<"\n"; for(pair<int,int>p:ans)cout<<p.first<<" "<<p.second<<"\n"; exit(0); } signed main(){ ios::sync_with_stdio(false);cin.tie(0); cin>>n; B=pow(n,0.333333333333); for(int i=1;i<B;i++){ basic_string<pair<int,int> >t; for(int j=i;j<=n;j+=B)t+={j,1}; if(t.size()){ for(int i=t.size()-1;i>=0;i--)ans+=t[i]; } } n/=B; if(n==0)out(); for(int i=1;i<B;i++){ basic_string<pair<int,int> >t; for(int j=i;j<=n;j+=B)t+={j*B,B}; if(t.size()){ for(int i=t.size()-1;i>=0;i--)ans+=t[i]; } } for(int i=B;i<=n;i+=B)ans+={i*B,B*B}; out(); return 0; } ```