Description
晴天有非常严重的选择恐惧症,每次吃饭前他都在纠结到底吃什么。。今天又到了吃饭的时候了。
重光:我给你一个包含n个不同整数的序列a,如果它所有连续子序列的价值和是素数咱们就吃米,不然就吃面。
定义一个序列的价值为序列中所有元素的最小值。
晴天:这不是分分钟给你算出来。
嗯…十分钟过去了,晴天选择死亡。
这个任务就交给你啦。
算出所有连续子序列的价值和。
Input
第一行输入一个整数t,代表有t组测试数据。
每组数据第一行包含一个整数n,表示序列a的元素个数。
接下来一行包含n个整数,表示序列a。
0<=n<=50000,1<=ai<=50000。
Output
对于每组数据输出一个整数,表示序列a的所有连续子序列的价值和。
Sample Input
1
3
1 2 3
Sample Output
10
分别求出ai左边最近且小于ai的位置L,和右边最近且小于ai的位置R,然后起点位于L+1到i,终点位于i到R-1的区间价值都为ai。
该数的贡献=该数的值×该数用的次数:
用的次数=两个区间长度的乘积
再一次用到了二分~~二分的用处好广呀~~
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
const int KL=60011;
struct node
{
int x,y;
}st[KL];
bool cmp(node a,node b)
{
return a.x<b.x;
}
int main()
{
int T,N,i;
long long ans,pl;
scanf("%d",&T);
while(T--)
{
scanf("%d",&N);
for(i=0;i<N;i++)
{
scanf("%d",&st[i].x);
st[i].y=i+2;
}
sort(st,st+N,cmp);
vector <int> v;
v.push_back(1);
v.push_back(N+2);
ans=0;
for(i=0;i<N;i++)
{
int k=st[i].y;
int pk=upper_bound(v.begin(),v.end(),k)-v.begin();
pl=(v[pk]-k)*(k-v[pk-1]);//不大于该数的两个区间
ans+=pl*st[i].x;//该数的贡献
v.insert(v.begin()+pk,k);//还原位置
}
printf("%lld\n",ans);
}
return 0;
}