[二分 单调队列] Atcoder AGC003 E. Sequential operations on Sequence

首先可以发现,如果 xi>xi+1 那么 xi 就是没用的,所以我们就倒过来求一个递减的序列

然后考虑第 i 次操作后的数列,肯定是由第 i1 次操作后的数列循环几次再加一个前缀得到的

而那个前缀也是由之前的某个前缀得到的,那么就二分一下,记一下每次操作会执行几次(也就是被后面的操作覆盖几次)

瞎搞一下

因为每次操作最多二分log次,所以总复杂度是 O(nlog2n)

#include 
#include 
#include 

using namespace std;

typedef long long ll;

const int N=100010;

int n,q,t;
ll b[N],Q[N],a[N],c[N];

inline char nc(){
  static char buf[100000],*p1=buf,*p2=buf;
  return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}

inline void read(int &x){
  char c=nc(); x=0;
  for(;c>'9'||c<'0';c=nc());for(;c>='0'&&c<='9';x=x*10+c-'0',c=nc());
}

inline void read(ll &x){
  char c=nc(); x=0;
  for(;c>'9'||c<'0';c=nc());for(;c>='0'&&c<='9';x=x*10+c-'0',c=nc());
}

inline void work(ll x,ll y){
  int p=upper_bound(Q,Q+1+t,x)-Q-1;
  if(!p) a[1]+=y,a[x+1]-=y;
  else c[p]+=y*(x/Q[p]),work(x%Q[p],y);
}

int main(){
  freopen("1.in","r",stdin);
  freopen("1.out","w",stdout);
  read(n); read(q);
  if(q==0){
    for(int i=1;i<=n;i++) printf("%d\n",1); return 0;
  }
  for(int i=1;i<=q;i++) read(b[i]);
  Q[++t]=b[q];
  for(int i=q-1;i;i--){
    if(b[i]>=Q[t]) continue;
    Q[++t]=b[i];
  }
  if(n1,Q+1+t);
  c[t]=1;
  for(int i=t;i>1;i--)
    c[i-1]+=c[i]*(Q[i]/Q[i-1]),work(Q[i]%Q[i-1],c[i]);
  for(int i=1;i<=n;i++) a[i]+=a[i-1];
  for(int i=1;i<=Q[1];i++) a[i]+=c[1];
  for(int i=1;i<=n;i++) printf("%lld\n",a[i]);
  return 0;
}

你可能感兴趣的:(单调队列,二分,&,三分,Thinking,Training)