bzoj4293: [PA2015]Siano
这题搞了我一晚上……因为某些傻X的问题……
窝这状态真是药丸TAT
这个题嘛……大家的题解都说线段树,时限也开了30s明摆着告诉你是nlogn……
不过我们发现a[i]<=10^6
那么我就有一个以空间换时间的做法,并且只需要用很小的空间就可以把复杂度降到O(n)(或者说是O(maxa[i]+n))
首先,这个被收割的稻草的A值显然有单调性,换句话说,每次收割都会有一个左端点
接着,我们发现,如果初始高度确定,生长时间确定,收割的门槛也确定,那么被收割的最低高度是可以算出来的
那么我们可以搞个单调栈,然后搞一搞就做完了
#include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #define ll long long #define N 1000006 using namespace std; inline ll read(){ ll ret=0;char ch=getchar(); while (ch<'0'||ch>'9') ch=getchar(); while ('0'<=ch&&ch<='9'){ ret=ret*10-48+ch; ch=getchar(); } return ret; } int n; ll a[N],s[N]; ll d[N/2],b[N/2],day; int stk[N/2],top; int to[N/2]; const int m=1e6; int main(){ n=read();day=read(); for (int i=1;i<=n;++i) ++a[read()]; for (int i=1;i<=day;b[i++]=read()) d[i]=read(); s[0]=a[0]=0; for (int i=1;i<=m;++i) s[i]=s[i-1]+(ll)a[i]*i; for (int i=1;i<=m;++i) a[i]+=a[i-1]; to[0]=d[0]=b[0]=0; top=0;stk[top++]=0; for (int k=1;k<=day;++k){ ll res=0; int last=m,x=max((ll)to[stk[top-1]],min((b[k]-b[stk[top-1]])/(d[k]-d[stk[top-1]]),(ll)m)); for (;x<last;x=max((ll)to[stk[top-1]],min((b[k]-b[stk[top-1]])/(d[k]-d[stk[top-1]]),(ll)m))){ res+=(d[k]-d[stk[top-1]])*(s[last]-s[x])+(b[stk[top-1]]-b[k])*(a[last]-a[x]); if ((last=x)>to[stk[top-1]]) break; if (!--top) break; } if ((to[k]=last)<m) stk[top++]=k; printf("%lld\n",res); } return 0; }