牛客练习赛 95 C-Division(思维,差分)

传送门

思路:

首先把数组中数字取对数,替换成需要进行除2操作的次数,之后从左到右扫描数组,每次尽可能选取比较大的区间进行 -1 操作,如果尽可能大都不满足 r − l + 1 ≥ k r−l+1≥k rl+1k ,则输出 -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;
}

结合差分的题解:
牛客练习赛 95 C-Division(思维,差分)_第1张图片
标程:

#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();
}

你可能感兴趣的:(#,思维,贪心,c语言,贪心算法,算法)