队友突然说给我这道题看看,看着好玩,做起来也挺好玩的,应该算是贪心吧。
题意:给出一段不大于N的区间,由单个数字组成,求出所有区间的最小元素的和。
首先可以看出,一个长度为N的区间的所有不同且不为空的子区间的数量是1+2+3+4······+N,即(N)(N+1)/ 2。
然后只要存在数字0属于只要区间(i , j),那么区间(i , j)最小元素必定为0。
存在数字1属于区间(i , j)且(i , j)区间里面的元素没有0存在,那么区间(i , j)最小元素必定为1。
如此类推2 , 3 , 4 ····9。
那么现在给出一个算法,从0 (其实0没意义,1就行)开始历遍到9。for(k = 1; k <=9 ;k++)
当区间(i , j)中所有数字大于等于k时候,设这段区间中所有子区间的最小值都为k,显然,这段区间的最小元素和等于(j - i - 1)(j - i) / 2 * k;
如果区间(i , j)中存在(x , y)所有元素都大于等于k+1,那么我们再设这个区间的最小值等于k+1,那么可以直接算出最小元素和,但是,注意,区间(x , y)中所有子区间已经在区间(i , j)中以最小值k算了一遍,所以只需要将原有值加上(y - x - 1)( y - x ) / 2 * 1即可算出可求值。如此类推,可以无重复缺漏算出所求,复杂度0(10n)。
#include <cmath>
#include <complex>
#include <cstdio>
#include<iostream>
#include <cstdlib>
#include<string>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 100005
#define MOD 1000000007
#define LL long long
char s[N];
LL cut(LL n)
{
if(n == 0 || n == 1)
return n;
else
return n*(n + 1) / 2;
}
int main()
{
LL n,i,j,k;
LL sum;
LL b,e;
while( cin>> n)
{
scanf("%s",s);
sum = 0;
LL l = strlen(s);
for(i = 1 ; i <= 9; i++)
{
for(j = b = e = 0;j < l; j++)
{
if(s[j] - '0' < i)
{
sum += cut(e - b);
b = e = 0;
}
else
{
e++;
}
}
sum += cut(e - b);
}
cout<<sum%MOD<<endl;
}
return 0;
}
2024

被折叠的 条评论
为什么被折叠?



