题目传送门
题目大意就是给一个数组,每次合并左边最小的两个数(左边的合并到右边去),一直合并到没法合并为止java
前几天与之前的ACM的队友们聊天,忽然感触良深.因而一块儿跑去CF作题了(一年没摸过了).
在作完这题以后我发现个人想法效率极低,因而我去问队友们都是怎么实现的,结果发现根据每一个人的特性,各自的作法都有些不一样. 其中,方案四算是咱们认为的最优解了.
另外能够根据每一个人的实现思考下我是怎么把简单的问题复杂化了....c++
这也是个人实现,效率真的低并且浪费资源,换一年前的本身根本不敢想象能写出这样的代码,看来真的是过久不思考了,麻木了.大家当笑话看吧 数组
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int n = scan.nextInt();
Long[] input = new Long[n];
TreeMap<Long, PriorityQueue<Integer>> positionMap = new TreeMap<>();
for (Integer i = 0; i < n; i++) {
input[i] = scan.nextLong();
PriorityQueue<Integer> position = positionMap.computeIfAbsent(input[i], aLong -> new PriorityQueue<>());
position.add(i);
}
TreeMap<Integer, Long> sortedMap = new TreeMap<>();
//每次从新获取迭代器.
for (Iterator<Long> iter = positionMap.keySet().iterator(); iter.hasNext(); iter = positionMap.keySet().iterator()) {
//数字
Long key = iter.next();
//将相同数据进行合并存入Map,新key为(key+key)
PriorityQueue<Integer> position = positionMap.get(key);
//若是大于1,进行合并操做
if (position.size() > 1) {
PriorityQueue<Integer> upgradePos = positionMap.get(key + key);
if (upgradePos == null) {
upgradePos = new PriorityQueue<>();
positionMap.put(key + key, upgradePos);
}
//是否升级到key+key
boolean upFlag = false;
//是否须要保留最后一个数(奇数保留)
boolean remainFlag = (position.size() & 1) == 1;
while (!position.isEmpty()) {
//数字位置
Integer pos = position.poll();
if (upFlag) {
upgradePos.add(pos);
}
if (remainFlag && position.size() == 1) {
break;
}
upFlag = !upFlag;
}
}
//当前key处理完,存入结果集,将key从原map中移除
if (!position.isEmpty()) {
sortedMap.put(position.poll(), key);
}
positionMap.remove(key);
}
//根据最终下标输出num
System.out.println(sortedMap.size());
Iterator<Integer> iterator = sortedMap.keySet().iterator();
while (iterator.hasNext()) {
System.out.print(sortedMap.get(iterator.next()));
if (iterator.hasNext()) {
System.out.print(" ");
}
}
System.out.println();
}
复制代码
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
const int maxn=150010;
const long long INF=(1ll<<60)-1;
typedef long long ll;
typedef pair<ll,int> pli;
map<ll,int> cnt;
//用来存储数字的数量
map<int,ll> ans;
priority_queue<pli,vector<pli>,greater<pli> >Q;
int main(){
//freopen("D://input.txt","r",stdin);
int n;
scanf("%d",&n);
//往队列内存入 {数字,下标} 的数据
for(int i=1;i<=n;i++){
ll a;scanf("%I64d",&a);
Q.push(make_pair(a,i));
cnt[a]++;
}
//遍历队列
while(!Q.empty()){
pli it=Q.top();Q.pop();
ll small=it.first;
int p=it.second;
//若是当前数字剩余数量大于1
if(cnt[small]>1){
//与下一个当前数字进行合并后入队列
cnt[small]-=2;
cnt[small*2]++;
pli it2=Q.top();Q.pop();
it2.first*=2;
Q.push(it2);
}
else{
//若只剩一个了,则存入结果集
cnt[small]--;
ans[p]=small;
}
}
printf("%d\n",ans.size());
for(map<int,ll>::iterator it=ans.begin();it!=ans.end();it++){
printf("%I64d ",it->second);
}
return 0;
}
复制代码
struct P{
int ss,lv,tos;
}p[150005];
struct Q{
int tos;
long long lv;
};
Q s[150005];
bool comp (P a, P b) {
if (a.ss != b.ss)
return a.ss < b.ss;
return a.tos < b.tos;
}
int main() {
int n;
scanf("%d",&n);
int a;
for (int i = 0; i < n; i++){
scanf("%d",&a);
int j = 1;
while(a % 2 == 0){
j *= 2;
a >>= 1;
}
p[i].ss = a;
p[i].lv = j;
p[i].tos = i;
}
sort(p, p + n, comp);
long long aa[150005];
memset(aa, 0, sizeof(aa));
int e = 0;
for (int i = 0; i < n;)
{
long long sum = 0;
int k = 0;
int j;
for (j = i ; j < n; j++ )
{
if (p[j].ss != p[i].ss)
break;
s[k].lv = p[j].lv;
s[k++].tos = p[j].tos;
sum += p[j].lv;
}
long long ans = p[i].ss;
i = j;
int b[50];
memset(b, 0, sizeof(b));
long long temp = sum;
int bb;
for (j = 0 ; temp; j++)
{
if (temp % 2){
b[j] = 1;
}
temp /= 2;
}
bb = j;
temp = 1;
for (j = 0; j < bb; j++){
int c = 0;
bool d = true;
for (int l = k - 1; l >= 0; l--){
if (s[l].lv == temp)
c++;
else
continue;
if (d && b[j]){
//printf("&%d %d %lld %lld\n", j, s[l].tos, temp, ans);
aa[s[l].tos] = ans * temp;
e++;
d = false;
}
if ((c + b[j]) % 2 == 1)
s[l].lv *= 2;
else
s[l].lv = 0;
}
temp *= 2;
}
}
printf("%d\n", e);
for (int i = 0, j = 0; i < n; i++){
if (aa[i]){
if (j)
printf(" ");
printf("%lld",aa[i]);
j++;
}
}
printf("\n");
}
复制代码
小笼包学弟摸上这题没多久就作完了,并且实现上也是最简单易懂的.咱们一致认为这种方法算是标解,算是方案一,二的最终进化版了.
实际上这道题的逻辑顺序就是从左到右执行,扫一次就能完成,前面的方法都有点想太多了.小笼包的作法是输入一个数就存入map,若已存在,则将这个数map中的值置为null,而后把(key:这个数*2,value:下标)存入这个map中(每次存入都得判断是否已存在).
优化
typedef long long lint;
const int MAXN = 2E5;
map<lint,int> mp;
vector<lint> ans;
lint n,cnt;
bool can[MAXN];
int main() {
while(scanf("%d",&n)!=EOF){
mp.clear(); ans.clear(); cnt = 0; memset(can,true,sizeof(can));
for(int i = 1; i <= n; ++i){
lint num; scanf("%I64d",&num); ans.push_back(num);
while(mp[num] != NULL){
ans[i - 1] *= 2; can[mp[num] - 1] = false; mp[num] = NULL; num *= 2; ++cnt;
}
mp[num] = i;
}
printf("%d\n",n - cnt);
for(int i = 0; i < ans.size(); ++i){
if(can[i]){
printf("%I64d ",ans[i]);
}
}
}
return 0;
}
复制代码