现在有n个货物,第i个货物的重量是 2wi2wi 。每次搬的时候要求货物重量的总和是一个2的幂。问最少要搬几次能把所有的货物搬完。
样例解释:
1,1,2作为一组。
3,3作为一组。
收起
输入
单组测试数据。 第一行有一个整数n (1≤n≤10^6),表示有几个货物。 第二行有n个整数 w1,w2,...,wn,(0≤wi≤10^6)。
输出
输出最少的运货次数。
输入样例
样例输入1 5 1 1 2 3 3
输出样例
样例输出1 2
今天遇到这道题可以说是我碰到一个难点了,我在网上搜索得知2^(n+1)=2^n+2^n
我们可以把所有相同的数合并,这样最后剩下几个数,就是我们要的结果了,以下是我自己熬一天写的代码:
#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1e6 + 5;
int d[N]={-1000};
int main() {
int a,b,c,e,f,g=0;
scanf("%d",&a);
for(b=1;b<=a;++b)
scanf("%d",&d[b]);
for(b=1;b<=a;++b)
for(c=b+1;c<=a;++c)
{
if(d[b]==d[c]) {d[b]=d[b]+1;d[c]=-1000;b--;break;}
}
for(b=1;b<=a;++b)
if(d[b]>0) g++;
printf("%d",g);
return 0;
}
通过这个代码我们发现仅仅只有四组过了,我经过一个改造,让其更简单的实现目标;
#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1e6 + 5;
int d[2*N];
int main() {
int a,b,c,e,f,g=0;
scanf("%d",&a);
for(b=1;b<=a;++b)
{scanf("%d",&c);
++d[c];}
for(b=0;b<2*N;++b)
{
g+=d[b]%2;
d[b+1]+=d[b]/2;
}
printf("%d",g);
return 0;
}
这一个代码可以说是非常非常非常巧妙了,首先,他将出现过货物的重量作为数组的下标,让它+1;比如说1 1 2 3 3
那么 d【1】为2,的d【2】为1,d【3】为2,d【4】为0;就是这样
for(b=0;b<2*N;++b)
{
g+=d[b]%2;
d[b+1]+=d[b]/2;
}重点在于这一段的处理,如果我们一位一位的算,如果d【b】%2==0,自然说明重量为2的b次方的货物有偶数个,那么就让他除2加到下一项,因为2^(n+1)=2^n+2^n,所以就转到下一项运行,如果d【b】%2!=0,说明为单,那么结果就是1,让g+1,则就是我们需要多运一趟,但是其并不影响 d[b+1]+=d[b]/2这一项运行,因为这是整数,所以d【b】/2与(d【b】-1)/2得到的是相同的结果。最终得到我们要的得数g即为我们需要跑的趟数