真假鉴定(upc新生赛)

        题意:有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;
    }
     
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值