传送门
思路:
首先把数组中数字取对数,替换成需要进行除2操作的次数,之后从左到右扫描数组,每次尽可能选取比较大的区间进行 -1 操作,如果尽可能大都不满足 r − l + 1 ≥ k r−l+1≥k r−l+1≥k ,则输出 -1 ,在从左到右一次次清零过程中,为了操作次数最少,我们可以贪心的想,每次操作后形成的序列非递减就可以了,加大一次性选取的区间长度
代码:
#include
#define ll long long
#define mod 1000000007
#define eps 1e-7
using namespace std;
const double PI = acos(-1);
const int N = 3e5 + 10;
int n, k;
void solve(){
cin >> n >> k;
vector<int> a(n + 10, 0);
vector<int> b(n + 10, 0);
for (int i = 1; i <= n; i++){
ll x;
cin >> x;
while(x)
a[i]++, x >>= 1;
a[i]--;
}
vector<pair<int, int>> ans;
for (int i=1,j ; i <= n ;){
if(!a[i])
i++;
else{
for (j = i; j <= n && a[j] > a[j - 1]; j++)
a[j]--;
if (j - i < k){
cout << -1 << '\n';
return;
}
ans.push_back({i, j - 1});
}
}
cout << ans.size() << '\n';
for (auto item : ans)
cout << item.first << " " << item.second << '\n';
}
int main(){
int _ = 1;
scanf("%d", &_);
while (_--){
solve();
}
return 0;
}
#include
using namespace std;
typedef long long ll;
int a[20005],n,m,fs;
struct Thing{
int l,r;
}ans[1000005];
void Clear(){
for(int i=1;i<=n+1;i++)a[i]=0;
}
void Solve(){
cin>>n>>m,fs=0;
for(int i=1;i<=n;i++){
ll x;
cin>>x;
while(x>1)x>>=1,a[i]++;
}
for(int i=n+1;i>=1;i--)a[i]-=a[i-1];
stack<int> s;
for(int i=1;i<=n+m;i++){
if(i-m>=1){
assert(a[i-m]>=0);
while(a[i-m])s.push(i-m),a[i-m]--;
}
if(a[i]<0){
while(a[i]){
if(!s.size())return puts("-1"),Clear();
ans[++fs]={s.top(),i-1},s.pop(),a[i]++;
}
}
}
if(s.size())return puts("-1"),Clear();
cout<<fs<<'\n';
for(int i=1;i<=fs;i++)cout<<ans[i].l<<' '<<ans[i].r<<'\n';
}
int main(){
int t;
cin>>t;
while(t--)Solve();
}