题意:有n堆硬币依次排列,每一堆有a_i个。每堆硬币全是真币或全是假币,真币每个重5克,假币每个重4克。你有一台电子天平,可以从每堆硬币中挑出若干个进行一次称量(也可以一个都不选)。现在你想要知道,若要确定前1,2,……,n堆硬币的真假,至少要称量几次。
题目还是很好的哈,特别是后面的处理,其实很容易想到2的次幂依次不影响,因为1+2+4<8,而且这个等比数论最长,所以取出这样的序列为一次,我们需要处理的就是把多的某一个次幂尽可能的均分到前面去,比如4 6 6 6 6,6可以取,1,2,4.所以我们让三个6分别取1,2,4.然后让剩下的自己,就是二组,考虑到nlog1e9,难搞呀,好像需要什么数据结构啥的,不行呢,所以我们考虑nloglog,1e8.也可哈,就按那个思路模拟就可以了,。
思路还是值得整理的,类似于倍增,但可以转换,高阶可以往低阶转换,让总序列的每一个数的最大值最小,就可以这样loglogn写了。
#include <bits/stdc++.h>
using namespace std;
const int maxx=1e6+100;
typedef long long ll;
inline bool read(ll &num){char in;bool IsN=false;in=getchar();if(in==EOF) return false;while(in!='-'&&(in<'0'||in>'9')) in=getchar();if(in=='-'){ IsN=true;num=0;}else num=in-'0';while(in=getchar(),in>='0'&&in<='9'){num*=10,num+=in-'0';}if(IsN) num=-num;return true;}
ll fac[maxx];
//ll cnm(int m,int n){if(m<n) return 0;return fac[m]*qpow(fac[m-n],mod-2)%mod*qpow(fac[n],mod-2)%mod;}
set<ll>st;
ll gcd(ll a,ll b){ if(b==0) return a; else return gcd(b,a%b);}
ll n,m;vector<ll>v[maxx];
ll a[maxx];
ll biaoji[500]={0};
ll yuan[500];
ll sum[300];
int main()
{
ll i,j,l,n,k;
ll cas=0;
ll t;
ll m;
cin>>n;
for(i=1;i<=n;i++) scanf("%lld",&a[i]);
ll geshu=1;
ll p1=0;
for(i=1;i<=n;i++)
{
if(a[i]==0)
{
printf("%lld\n",p1);
continue;
}
ll p=1;
for(j=1;j<=30;j++)
{
if(p<=a[i]&&2*p>a[i])
{
biaoji[j]++;
// printf("%lld\n",j);
break;
}
p=p*2;
}
sum[0]=0;
for(j=1;j<=30;j++)
{
sum[j]=sum[j-1]+biaoji[j];
yuan[j]=biaoji[j];
}
ll maxl=0;
for(j=2;j<=30;j++)
{
ll p=sum[j]/j;
if(sum[j]%j!=0) p++;
//printf("%lld****\n",p);
for(k=1;k<j;k++)
{
if(yuan[k]<p)
{
if(yuan[j]>=(p-yuan[k]))
{
yuan[j]-=(p-yuan[k]);
yuan[k]=p;
}
}
}
}
//for(j=1;j<=30;j++) printf("%d ",yuan[j]);
for(j=1;j<=30;j++) maxl=max(maxl,yuan[j]);
printf("%lld\n",maxl);
p1=maxl;
}
}