首页 > 代码库 > BZOJ 3745

BZOJ 3745

分治.....

之前就了解过这种分治统计答案的算法,对于当前的区间[l,r],我们考虑过中间的那条线的区间,这种题往往都存在单调性,我们发现min和max都是随位置单调的,我们枚举左端点x,然后维护两个指针p1,p2,表示[mid+1,p1/p2]这个区间的最值大于/小于[x,mid]的最值的最远的p1/p2,那么答案就可以分3段统计,一段是[mid+1,min(p1,p2)],右端点在这一部分的区间的min和max都一样,比较容易求出。另一段是[max(p1,p2)+1,r],在这一部分的区间min和max为[mid+1,y]的最值,考虑答案的式子可以拆成:∑min*max*r-∑min*max*(l-1),那么我们就可以预处理出min*max*r和min*max的前缀和,然后就可以算出这一部分对答案的贡献。最后一段是[min(p1,p2)+1,max(p1,p2)],这个对答案的贡献和上一个和像,维护2个前缀和即可。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 #define maxn 500005
 6 typedef long long LL;
 7 const int mo=1000000000;
 8 int n,a[maxn];
 9 LL ans,sum1[maxn][2],sum2[maxn][2],sum3[maxn][2];
10 
11 inline int read(void)
12 {
13     int x=0;
14     char ch=getchar();
15     while (ch>9||ch<0) ch=getchar();
16     while (ch>=0&&ch<=9)
17     {
18         x=x*10+ch-0;
19         ch=getchar();
20     }
21     return x;
22 }
23 
24 void solve(int l,int r) 
25 {
26     if (l==r) 
27     {
28         ans=(ans+(LL)a[l]*a[l])%mo;
29         return;
30     }
31     int mid=(l+r)>>1;
32     int mn=1e9,mx=-1;
33     sum1[mid][0]=sum1[mid][1]=0;
34     sum2[mid][0]=sum2[mid][1]=0;
35     sum3[mid][0]=sum3[mid][1]=0;
36     for (int i=mid+1;i<=r;i++)
37     {
38         mn=min(mn,a[i]);
39         mx=max(mx,a[i]);
40         sum1[i][0]=(LL)mn*mx%mo*i%mo;sum1[i][1]=(LL)mn*mx%mo;
41         sum2[i][0]=(LL)mn*i%mo;sum2[i][1]=mn;
42         sum3[i][0]=(LL)mx*i%mo;sum3[i][1]=mx;
43     }
44     for (int i=mid+2;i<=r;i++) 
45     {
46         (sum1[i][0]+=sum1[i-1][0])%=mo;(sum1[i][1]+=sum1[i-1][1])%=mo;
47         (sum2[i][0]+=sum2[i-1][0])%=mo;(sum2[i][1]+=sum2[i-1][1])%=mo;
48         (sum3[i][0]+=sum3[i-1][0])%=mo;(sum3[i][1]+=sum3[i-1][1])%=mo;
49     }
50     mn=1e9,mx=-1;
51     int t1=a[mid+1],t2=a[mid+1];
52     int p1=mid,p2=mid;
53     for (int i=mid;i>=l;i--) 
54     {
55         mn=min(mn,a[i]);mx=max(mx,a[i]);
56         while (t1>=mn&&p1<r) p1++,t1=min(t1,a[p1+1]);
57         while (t2<=mx&&p2<r) p2++,t2=max(t2,a[p2+1]);
58         int tmp=min(p1,p2);
59         LL w=(LL)(mid+2-i+tmp-i+1)*(tmp-mid)/2;w%=mo;
60         ans=(ans+w*mn%mo*mx%mo)%mo;
61         tmp=max(p1,p2)+1;
62         w=(sum1[r][0]-sum1[tmp-1][0]+mo)%mo;
63         w=(w-(sum1[r][1]-sum1[tmp-1][1]+mo)%mo*(i-1)%mo+mo)%mo;
64         ans=(ans+w)%mo;
65         if (p1<=p2) 
66         {
67             w=(sum2[p2][0]-sum2[p1][0]+mo)%mo*mx%mo;
68             w=(w-(sum2[p2][1]-sum2[p1][1]+mo)%mo*(i-1)%mo*mx%mo+mo)%mo;
69             ans=(ans+w)%mo;
70         }
71         else 
72         {
73             w=(sum3[p1][0]-sum3[p2][0]+mo)%mo*mn%mo;
74             w=(w-(sum3[p1][1]-sum3[p2][1]+mo)%mo*(i-1)%mo*mn%mo+mo)%mo;
75             ans=(ans+w)%mo;
76         }
77     }
78     solve(l,mid);
79     solve(mid+1,r);
80 }
81 
82 int main()
83 {
84     n=read();
85     for (int i=1;i<=n;i++) a[i]=read();
86     solve(1,n);
87     printf("%lld\n",ans);
88     return 0;
89 }

 

BZOJ 3745