SPOJ

Enough with this Harry Potter, please! What are we, twelve-year olds?  Let's get our teeth into some real pumpkin pasties -- oops, programming problems!

Here we go!

Let's define the diversity of a list of numbers to be the difference between the largest and smallest number in the list.

For example, the diversity of the list (1, -1, 2, 7) = 7 - (-1) = 8.

A substring of a list is considered a non-empty sequence of contiguous numbers from the list. For example, for the list (1,3,7), the substrings are (1), (3), (7), (1,3), (3,7), (1,3,7). A subsequence of a list is defined to be a non-empty sequence of numbers obtained by deleting some elements from the list. For example, for the list (1,3,7), the subsequences are (1), (3), (7), (1,3), (3,7), (1,7), (1,3,7).

Given a list of length N find the number of substrings and subsequences in this list with the maximum diversity. If a substring/subsequence having maximum diversity occurs multiple times in the list, each of its occurences adds towards the answer.   And tell Harry Potter your answer

Input (STDIN):

The first line contains T, the number of test cases. Then follow T test case blocks.

Each blocks starts with the first line containing the number N.

The second line contains a list of numbers in this list.

Output (STDOUT):

For each test case, output the number of substrings and the number of subsequences in this list with the maximum diversity.

Since the answers maybe very large, output them modulo 1000000007.

Constraints:

T <= 10

N <= 100,000

Each number in the list is between 1 and 100,000 inclusive.

Sample Input:

3

3

1 2 3

4

1 4 3 4

3

3 2 1

Sample Output:

1 2

3 6

1 2

 题意:给你一串数字,给出一个差异性的定义(这串数字中最大值和最小值的差),问你这串数字的连续字串和非连续字串中差异性和原串相同的各有几个。

思路:连续的字串我们可以这样求

例:3 5 1 4 3 5 2 3 

定义a,b分别是当前最小值和最大值的位置

a=0,b=0

for循环从i=1遍历到i=8(n=8),s[是存原串的数组

for(i=1;i<=n;i++){

  if(s[i]==mx)//mx是最大值

  {

    b=i;

  }

  if(s[i]==mn)//mn是最小值

  {

    a=i;

  }

  sum=(sum+min(a,b))%mod;

}

为什么可以这样呢

当i=1时,对于i<=1的所有字串,没有任何字串的差异性可以和原串相等(因为它没有原串的最大值和最小值),所以sum=sum+0;

当i=2时,对于i<=2的所有字串,没有任何字串的差异性可以和原串相等(因为它只有原串的最大值),所以sum=sum+0;此时b=2;

当i=3时,对于i<=3的所有字串,原串的最大值和最小值都可以在i<=3中找到,我们以2<=i<=3为基本串,在它前面再加上连续的数字

可以找到2种情况(5,1[基础串])(3,5,1),此时a=3,b=2;所以sum=sum+min(a,b)=2;

当i=4时,,原串的最大值和最小值都可以在i<=4中找到,而我们可以再i=3的基础上在后面加上连续的数字,又可以找到两种新的情况(5,1,4)

(3,5,1,4);此时a=3,b=2;sum=sum+min(a,b)=4;

当i=5时,,原串的最大值和最小值都可以在i<=5中找到,而我们可以再i=4的基础上在后面加上s[5],又可以找到两种新的情况(5,1,4,3)

(3,5,1,4,3);此时a=3,b=2;sum=sum+min(a,b)=6

当i=6时,,因为s[6]是最原串的最大值,所以我们可以把基础串往后移一些(往后移了以后得到的子串数可以更多(1,4,3,5[基础串])(5,1,4,3,5),(3,5,1,3,4,5)),此时a=3,b=5,我们可以发现每次加的个数等于a,b中最小的那个,因为假设我们的基础串前面有3个数字,

我们可以选择加倒数第一个;选倒数第一个和倒数第二个;选倒数第一,倒数第二,倒数第三个。一共三种情况(因为要连续的),所以基础串前面的数字的个数越多越好。

而算不连续串时,我们可以用到容斥定理来算s【既有最大又有最小的串数】=s【总数】-s【没有最大】-s【没有最小】+s【既没最大又没最小】;

代码:

·

#include<stdio.h>
#define INF 0x7fffffff
#define ll long long
#define mod 1000000007
ll s[100050];
ll bin[100050];
ll min(int a,int b){
	if(a>b)
	return b;
	return a;
}
void init(){
	ll i;
	ll r=1;
	bin[0]=1;
	for(i=1;i<=100005;i++){
		r=(r*2)%mod;
		bin[i]=r;
	}
}
int main(){
	int t;
	init();
	int n,i,j;
	ll mx1,mn1,mx,mn;
	scanf("%d",&t);
	while(t--){
		mx=mn=1;
		mx1=0;
		mn1=INF;
		scanf("%d",&n);
		for(i=1;i<=n;i++){
			scanf("%lld",&s[i]);
			if(s[i]<mn1){
				mn=1;
				mn1=s[i];
			}
			else if(s[i]==mn1)
			mn++; //计算最小值的个数 
			if(s[i]>mx1){		
				mx=1;
				mx1=s[i];
			}
			else if(s[i]==mx1)
			mx++;
		}
		ll a=0,b=0;
		ll sum=0;
		for(i=1;i<=n;i++){
			if(s[i]==mn1)
			a=i;
			if(s[i]==mx1)
			b=i;
			//printf("%d %d
",a,b);
			sum=(min(a,b)+sum)%mod;
		}
		ll ans=0;
		if(mn1!=mx1){//判断特殊情况,如果最大值和最小值相等时,就说明整个数列都是同一个数,那么满足条件的非连续子序列的个数就是2的n次方-1 
			ans=(bin[n]-bin[n-mn]-bin[n-mx]+bin[n-mx-mn]+mod)%mod;
			if(ans<0)//因为可能出现一种极端情况(bin[n-mx]和bin[n-mn]的值都接近与mod,bin[n]和bin[n-mx-mn]的值接近于0,ans的值就可能是负数) 
			ans+=mod;//在这里wa了七八发,知道真相的我感觉要吐血了 
		}
		else
		ans=(bin[n]-1+mod)%mod;
		printf("%lld %lld
",sum,ans);
	}
	return 0;
}

  

原文地址:https://www.cnblogs.com/cglongge/p/9304401.html