序列问题
Description
Input
輸入文件名為seq.in。
首先輸入n。
接下來輸入n個數,描述序列 A。
Output
輸出文件名為seq.out。
輸出一行一個整數代表答案。
Sample Input
7
0 35 40 45 56 65 94
Sample Output
66636
Data Constraint
對于30%的數據,n<=5000
對于60%的數據,n<=50000
對于100%的數據,n<=500000,0<=A[i]<=10^9
.
.
.
.
.
分析
這題竟然用很神奇的分治?!
對于區間[x…y],將它分成三部分:
m = (x +y)/2
1.左右端點都在[x…m]里的。
2.左右端點都在[m + 1…y]里的。
3.左右端點在m的兩旁。
前兩個遞歸處理,考慮第三個怎么求,這是分治的常規套路。
先考慮區間[m + 1…y](右區間),以m+1為左端點,從左往右枚舉右端點,min值會不斷變小,max值會不斷變大,將變化的地方存下來,分別放進兩個數組里,設為a,b。
現在還要考慮區間[x…m](左區間),從m出發,從右往左枚舉左端點l,記錄下min值和max值,設為min_l,max_l。
最后需要將兩個區間合并。
在a數組里找到代表的值第一個小于min_l的位置u(從左往右看),
在b數組里找到代表的值第一個大于max_l的位置v(從左往右看)。
這個可以二分。
由于min_l不斷縮小,max_r不斷變大,也可以直接維護個指針。
右端點r的取法接下來有四種情況:
1.r < min(u, v),min_[l…r] = min_l, min_[l…r] = min_r。
2.r >= max(u, v), min_[l…r] = [l…r]里的點到m+1的最小值,max_[l…r] = [l…r]里的點到m+1的最大值。
3…u <= v, u<=r < v,min_[l…r] = [l…r]里的點到m+1的最小值,max_[l…r] = min_r。
4.u >v, v<=r < u,min_[l…r] = min_l,max_[l…r] = [l…r]里的點到m+1的最大值。
1可以直接算。2、3、4維護前綴和就行了。
.
.
.
.
程序:
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> using namespace std;long long mo=1000000007; long long ans=0; long long n,a[500005],u[500005],v[500005],s1[500005],s2[500005],s3[500005];void fz(long long x,long long y) {if (x>y) return;if (x==y){ans=(ans+a[x]*a[x]%mo)%mo; return;}long long mid=(x+y)/2;fz(x,mid); fz(mid+1,y);long long uu=1,vv=1;u[1]=v[1]=mid+1;s1[mid]=s2[mid]=s3[mid]=0;s1[mid+1]=s2[mid+1]=a[mid+1];s3[mid+1]=a[mid+1]*a[mid+1];for (int i=mid+2;i<=y;i++){if (a[i]<a[u[uu]]) u[++uu]=i;if (a[i]>a[v[vv]]) v[++vv]=i;s1[i]=(s1[i-1]+a[u[uu]])%mo;s2[i]=(s2[i-1]+a[v[vv]])%mo;s3[i]=(s3[i-1]+a[u[uu]]*a[v[vv]])%mo;}long long minn=2147483647,maxx=-2147483647,l=1,r=1;long long sum=ans;for (int i=mid;i>=x;i--) {minn=min(minn,a[i]);maxx=max(maxx,a[i]);while (l<=uu&&minn<=a[u[l]]) l++;while (r<=vv&&maxx>=a[v[r]]) r++;long long l1,r1;if (l>uu) l1=y; else l1=u[l]-1;if (r>vv) r1=y; else r1=v[r]-1;if (min(l1,r1)>mid) ans+=(long long)(min(l1, r1)-mid)*minn%mo*maxx%mo;if (max(l1,r1)<y) ans+=s3[y]-s3[max(l1,r1)];if (l1<=r1) ans+=(long long)(s1[r1]-s1[l1])*maxx%mo; else ans+=(long long)minn*(s2[l1]-s2[r1])%mo;ans=(ans%mo+mo)%mo;} } int main() {freopen("seq.in","r",stdin);freopen("seq.out","w",stdout);scanf("%lld",&n);for (int i=1;i<=n;i++) scanf("%lld",&a[i]);fz(1,n);printf("%lld",ans);fclose(stdin);fclose(stdout);return 0; }轉載于:https://www.cnblogs.com/YYC-0304/p/10458938.html
總結
- 上一篇: 袁绍的刁难
- 下一篇: 【五校联考3day2】A