吞噬算法

来源:互联网 发布:骨科空心钉 知乎 编辑:程序博客网 时间:2024/06/10 14:37

O(kn)
咳咳,这是“力量”同学乱搞搞出来的吞噬算法,其主旨就是吃。。。(话说多少算法不是乱搞搞出来的)

题目描述

【题目描述】
WZK 最近收到了一个任务。
给出一个 n 个数的序列,为 A0,A1,„„,An-1,循环移动 k 位之后,这个序列就变 成了 Ak,Ak+1,„„,An-1,A0,A1,„„,Ak-1。一种优秀的循环移动是,对于任意的 前 i(1<=i<=n)项和都满足不小于零。请给出这个序列优秀循环移动的个数。
这道题目当然是很简单啦,但是 WZK 忙着吃小浣熊干脆面,手上油油的写不了程序,于是就麻烦你啦!如果能做到满分,他就会考虑请你吃一包哦~
【输入格式】
第一行一个整数 n(1 <= n <= 10^6),表示有 n 个数。
第二行 n 个整数,Ai(-1000 <= Ai <= 1000)表示给出的第 i 个数。
【输出格式】 一行一个整数,表示优秀循环移动的个数。
【样例输入】
one:
3
2 2 1
two:
4
-3 5 1 2
【样例输出】
one:
3
two:
2
然后luogu出在了月赛题里
uim在公司里面当秘书,现在有n条消息要告知老板。每条消息有一个好坏度,这会影响老板的心情。告知完一条消息后,老板的心情等于之前老板的心情加上这条消息的好坏度。最开始老板的心情是0,一旦老板心情到了0以下就会勃然大怒,炒了uim的鱿鱼。
uim为了不被炒,知道了了这些消息(已经按时间的发生顺序进行了排列)的好坏度,希望研究如何不让老板发怒。
uim必须按照时间的发生顺序逐条将消息告知给老板。不过uim可以使用一种叫“倒叙”的手法,例如有n条消息,小a可以从k,k+1,k+2…n,1,2…k-1这种顺序通报。
他希望知道,有多少个k,从k开始通报到n然后从1通报到k-1可以让老板不发怒。

基础思路

简单看来这就是一个环,选能走下来的位数和一直不小于0的数。。。样例和没有没区别。然而环,单调队列神马的都太复杂了,现在请参考吞噬算法——
产生随机数 7,1,-5,2,-3(n=5)
首先,从第一位开始扫到第一个负数-5,然后用-5 吃掉前一个数1 ,于是变成了7, -4 ,2,-3
看来,一个1 满足不了-5 的胃口,于是接着往下吃 3 ,2,-3 .
呃,-4 撑死了……那就接着往下揍,找到了-3-3 吃了2 ,变成3,-1,再往前吃,就成了2,好了,只剩下正数了,于是输出正数的个数 1
P版代码——

var n,s,i:longint;  a:array[1..1000005] of integer;  b:array[1..1000005] of longint;begin  assign(input,'sum.in'); assign(output,'sum.out');  reset(input); rewrite(output);  readln(n);  for i:=1 to n do read(a[i]);  i:=0;  while i<n do  begin    inc(i);    inc(s);    b[s]:=a[i];    if a[i]<0 then    begin      while (b[s]<0) and (s>1) do      begin        dec(s);        b[s]:=b[s]+b[s+1];        b[s+1]:=0;      end;      while b[s]<0 do      begin        b[s]:=b[s]+a[n];        dec(n);        if n<i then begin                      writeln(0);                      close(input);                     close(output);                     end;      end;    end  end;  writeln(s);  close(input); close(output);end.

通俗解释

那么,通俗点说呢,首先找到-5,要想成立,-5前面的和必须比0大,于是-5必须在1后面。同理,7,1,-5这个顺序不能打乱。于是推到最后,就行了。

栈实现

这里是用栈来实现

这里写图片描述

另一种解释

然后另一组随机数据-3,5,1,2 怎么办?
依然很简单。先将a【1】a【4】吞噬了(a【i】,a【n】) 然后n– 直到a【1】 再push

这里写图片描述

#include<stack>#include<iostream>using namespace std;int a[1000000+2],n;stack<int>s;int main(){    cin>>n;    for(int i=1;i<=n;i++)    cin>>a[i];    for(int i=1;i<=n;i++)    if(a[i]>0) s.push(a[i]);    else{         while(!s.empty()&&a[i]<0){             int t=s.top();             a[i]+=t;             s.pop();         }         if(a[i]<0)while(a[i]<0&&n>i)              a[i]+=a[n--];              if(a[i]<0){                  cout<<0;                  return 0;               }               s.push(a[i]);         }    cout<<s.size();    return 0;}

所有元素最多读一次,进栈一次,出栈一次,最少读一次,进栈一次。这个时间复杂度可以处理任何数据(时间复杂度再高就读不进了)。故此算法时间复杂度(kn)k属于[2,3)。

0 0
原创粉丝点击