对于每一个数,要将其不断除2变成1,应该要进行log2(n)次处理,所以就不用再考虑原数组,而是另外建一个数组来存它所需要的操作次数。
每次对该数组进行差分,不妨从i到n开始遍历,每次遇到已经减为0的元素就跳过,否则,找到之后的最大的j满足mas[j]>mas[j-1],来保证在mas[j-1]减完之后才轮到mas[j],从而使我们的操作具备从左往右一次遍历的合理性(为什么不是 mas[j]>=mas[j-1]?因为在mas【j】之前mas【j-1】已经减过一次了,如果此时仍要满足mas[j]>=mas[j-1],就意味着原本的mas[j]可能小于mas[j-1],那就不合理了)
for( j=i;j<=n&&mas[j]>mas[j-1];++j)
mas[j]--;
if(j-i<k){
cout<<-1<<"\n"<<endl;
return ;
}
vt.push_back(make_pair(i,j-1));
}
然后就乖乖模拟就好了。
这里主要想讲一讲log函数。一开始我是用的log来求出每个数至少要除多少次2才能得到1,但是log有个问题,就是精度可能不够。这里mas【i】的上限是1e15,而double的精度是15-16位,就有可能在浮点运算上出现问题,从而导致出错。(让我wa了好几发)
所以可以直接对每一个数跑一边o(log)的循环,当然,多组样例记得清空。
while(d)
{
mas[i]++;
d>>=1;
}
mas[i]--;
另外还有一种o(1)的求法。
因为我们其实就是在求最高位的1是第几位
先把最高位的1向下传,让所有位都变成1。
然后分治统计1的个数
ac代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
ll t,n,k,d;
ll mas[20000];
vector<pair<ll,ll>> vt;
void solve(){
ll j;
for(int i=1;i<=n;){
if(!mas[i]){
i++;
continue;
}
for( j=i;j<=n&&mas[j]>mas[j-1];++j)
mas[j]--;
if(j-i<k){
cout<<-1<<"\n"<<endl;
return ;
}
vt.push_back(make_pair(i,j-1));
}
cout<<vt.size()<<"\n";
for(auto &[x,y]:vt){
cout<<x<<" "<<y<<'\n';
}
}
int main()
{ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
cin>>t;
while(t--){
vt.clear();
memset(mas,0,sizeof mas);
cin>>n>>k;
for(int i=1;i<=n;++i){
cin>>d;
while(d){
mas[i]++;
d>>=1;
//mas[i]--;
}
mas[i]--;
// mas[i]=(ll)(log((double)d)/log(2.000)*1.00000);
// cout<<mas[i]<<" ";
}
solve();
}
}