Vijos 3764 牛奶题

来源:互联网 发布:cms监控软件操作说明 编辑:程序博客网 时间:2024/06/05 05:00
【问题描述】 
       这是一道魔改的奶牛题,所以被称为牛奶题。 
  wdz的牛奶厂里面有N桶排成一排的牛奶,每一桶牛奶都有一个品质值。我们为wdz定义如下的一种操作:选择两桶相邻的品质值相同(设为X)的牛奶,通过奥妙重重的步骤,合并为一桶品质值为X+1的牛奶并放在原来的位置(此时原来的两桶牛奶已经被取走)。 
  wdz想要通过若干次上述操作得到一桶品质值尽可能大的牛奶(即最大化 所有牛奶品质值中的最大值 ),但是wdz日理万机非常繁忙,所以他请你来帮忙求出这个最大值。 
【输入格式】 
       输入的第1行一个非负整数n,意义见题目描述。第2到n+1行共n个正整数,第i个数表示第i桶牛奶的品质值,数组保证最初的品质值均为1到40之间的整数(也就是说在操作之后最大值超过40是被允许的)。 
【输出格式】 
       输出一行一个整数表示答案。 
【输入样例】 









【输出样例】 

【数据范围】 
        对于30%的数据,保证n<=2,000 

        对于100%的数据,保证n<=300,000,最初给出的品质值均为不超过40的正整数。



由于对品质值小的桶进行合并不会限制对品质值大的桶的合并,可以发现合并操作是无后效性的,自然而然地考虑贪心,由小到大合并,每次合并连续相等的一段桶,按长度为奇数/偶数分类讨论。

设合并前桶的品质值为X:

(1)如果连续项长度为偶数(假设有2*k桶),两两合并成k桶,每桶品质值为X+1即可。(每次合并品质值只+1,还能合并的情况之后再考虑)

(2)如果连续项长度为奇数(假设有2*k+1桶),则无论怎样合并,都会单独剩下一桶无法合并,又由于我们是按桶的品质由小到大合并的,则剩下的这一桶以后也不会再被合并了,所以以它作为分隔,其左右两边的桶被划分成两个互不影响的部分。现在的问题是我们合并出了k桶品质值为X+1的桶,我们应该将它们放在分隔桶的右边还是放在左边?事实证明我们事先是不知道该放在哪边的, 所以我们可以选择一种很巧妙的放置方式------我们在左右两边都各放置k桶品质值为X+1, 虽然实际上这是不可能的,但由于分隔桶的划分,这样做对最后的答案并没有影响。

上述操作可以用链表实现,最后遍历所有的桶找出品质值最大的那一桶即可。

另:牛奶桶可能的极大品质值为40+log2(300000),约为58。

#include<cstdio>#include<cstring>#include<algorithm>#include<iostream>using namespace std;const int maxn=300000+5;const int inf =1e8;int N;struct Chain{int from;int v;int to;}Bucket[maxn];void init(){scanf("%d",&N);for(int i=1;i<=N;i++){scanf("%d",&Bucket[i].v); Bucket[i].from=i-1;Bucket[i].to=i+1;}Bucket[N+1].from=N; //(1)return;}void solve(){   int i,k,e,mid,cnt,ans;   for(i=1;i<=57;i++)   {     for(k=1;k<=N;k=Bucket[k].to)     if(Bucket[k].v==i)     {      e=k,cnt=0;      while(e<=N&&Bucket[e].v==i)  {cnt++;e=Bucket[e].to; } e=Bucket[e].from; //如果不写(1)这一步,(2)这一步后e=0,将进入死循环。  if(cnt%2) { mid=k; for(int j=1;j<=(cnt-1)/2;j++) mid=Bucket[mid].to; for(int p=k;p!=mid;p=Bucket[p].to) Bucket[p].v++; for(int p=e;p!=mid;p=Bucket[p].from) Bucket[p].v++; } else {   mid=k;   for(int j=1;j<cnt/2;j++) mid=Bucket[mid].to;   Bucket[mid].to=Bucket[e].to;   Bucket[Bucket[e].to].from=mid;   mid=Bucket[mid].to;   for(int p=k;p!=mid;p=Bucket[p].to) Bucket[p].v++; } k=e;     }   }     ans=0;   for(k=1;k<=N;k++)   ans=max(ans,Bucket[k].v);   printf("%d\n",ans);   return;}int main(){//freopen("in.txt","r",stdin);//freopen("out.txt","w",stdout);init();solve();return 0;}





原创粉丝点击