0707灵动集训

团结力量大

Description

为了让大家体会团结力量大,高老师决定带领大家做一个活动,她把同学们分成了 n 个小组,每组 m 个同学,每个同学手里有一个自然数。

她让每组内的同学按如下方式合并成团:

  • 初始时每人是一个团,每人手里的数字为该团的分数
  • 每次可以将两个团合并成为一个新团,分数为原来两个团的分数乘积+1,例如:两个分数分别为 35 的团,合并后的新团分数为 \(3\times 5 + 1 = 16\)
  • 每组同学按上述方式合并,直至整个组合并为一个团

高老师的学生都非常聪明,现在她想知道,每个组最高合并出的分数是多少?答案保证在 \(2^{63}-1\) 以内。

Format

Input

第一行输入两个整数 \(n,m(1\le n\le 500000, 1\le m \le 20)\)

第二行开始,每行输入 \(m\) 个整数,表示一个组中每位同学的分数\((0\sim 7)\)

Output

n 行,每行一个整数,表示对应的组可以合并出的最高分。

Editorial

this problem seems like "合并果子" in which it can be proved that choosing the smallest value always gives the maximum answer.

Actually,this problem has the same editorial with it : always select the smallest.

Using priority queue it's quite a well solution,but in this question,Time complexity should to be close to \(O(n)\).therefore,we can use bucket sort to replace std::sort,and optimizing priority queue with normal queues.

we assume that queue q has all the result of the merge. obviously,the elements in q are monotonically increasing. therefore,the smallest elements is between the sorted array \(a\) and the front of the queue \(q\).

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
queue<ll>x,y;
//get the minimum between two queues 
ll Get() {
	int x1 = -1;
	if(x.size())
		x1 = x.front();
	int y1 = -1;
	if(y.size())
		y1 = y.front();
	if(x1==-1) {
		y.pop();
		return y1;
	}
	if(y1==-1) {
		x.pop();
		return x1;
	}
	if(x1<y1) {
		x.pop();
		return x1;
	} else {
		y.pop();
		return y1;
	}
}

int main() {
	int n,m;
	cin >> n >> m;
	while(n--) {
		// clear
		while(x.size())
			x.pop();
		while(y	.size())
			y.pop();
			
		vector<ll>a(m);
		for(auto &i:a)
			cin >> i;
		if(m==1) {
			cout << a[0] << endl;
			return 0;
		}
		sort(a.begin(),a.end());
		for(auto &i:a)
			x.push(i);
		while(x.size()!=0||y.size()!=1) {
			ll n1 = Get(), n2 = Get();
			y.push(n1*n2+1);
		}
		cout << y.front() << endl;
	}
}
posted @ 2022-07-08 10:57  seekerHeron  阅读(38)  评论(0)    收藏  举报