SPOJ - AMR11H

题目链接:https://vjudge.net/problem/26260/origin

题目大意:给出一个数串,定义数串的多样性值为数串中的最值差;又定义两种数串:连续子串和随机子串。

     求所有的连续子串和随机子串中多样性值与母串相等的个数。

思路:一个母串,其连续子串的总数为(1+n)*n/2;随机子串的总数为2^n-1;连续子串的多样性值相等数可以通过一个遍历和一个递加等式求出,这等式等下给出详细解释(感觉很神奇)。而随机子串的多样性值相等数=总数-没有最小值的随机子串数-没有最大值的随机子串数+既没有最大值也没有最小值的子串数。(可以画图自行证明,有个博客说是容斥原理),其中有个最大值和最小值相等的情况,要做特殊处理。

以下为ac代码:

 1 #include<iostream>
 2 #define mod 1000000007
 3 using  namespace std;
 4 int max(int a,int b){ return a>b?a:b; }
 5 int min(int a,int b){ return a>b?b:a; }
 6 int num[100001];
 7 int main()
 8 {
 9     int n,a[100001];
10     num[0]=1;
11     for(int i=1;i<=100000;i++)
12     num[i]=num[i-1]*2%mod;
13     while(cin>>n)
14     {
15         int m;
16         long long int sum1,sum2;
17         while(n--)
18         {
19             cin>>m;
20             int maxn=-1,minn=100001;
21             sum1=sum2=0;
22             for(int i=1;i<=m;i++)
23             {
24                 cin>>a[i];
25                 maxn=max(a[i],maxn);
26                 minn=min(a[i],minn);
27             }
28             if(maxn==minn)
29             {
30                 sum1=((1+m)*m/2)%mod;
31                 sum2=num[m]-1;
32                 cout<<sum1<<" "<<sum2<<endl;
33             }
34             else
35             {
36                 int t=0,p=0,t1=0,p1=0;
37                 for(int i=1;i<=m;i++)
38                 {
39                     if(a[i]==minn)
40                     {
41                         t=i;
42                         t1++;
43                     }
44                     if(a[i]==maxn)
45                     {
46                         p=i;
47                         p1++;
48                     }
49                     sum1=(sum1+min(t,p))%mod;
50                     //cout<<sum1<<" "<<min(t,p)<<endl;
51                 }
52                 sum2=(num[m]-1-num[m-t1]+1-num[m-p1]+1+num[m-t1-p1]-1)%mod;
53                 if(sum2<0)
54                 sum2+=mod;
55                 cout<</*maxn<<" "<<minn<<" "<<p<<" "<<p1<<" "<<*/sum1<<" "<<sum2<<endl;
56             }
57         }
58     }
59     return 0;
60 }

参考博客网址:http://www.cnblogs.com/chenyang920/p/4743955.html

以下是对遍历求和sum1的详细解释:给出3 2 4 1 3 1 2数串,初始化t,p所指位置为0,起始位置为a[1]=3;min(t,p)为最值最小坐标,其实这个就是满足的子串有多少个了;当i遍历到第一个最大值4时,p值为i=3,但t由于未找到最小值依然为0,故min(t,p)依然为0,sum1也还是0,说明目前没有符合的子串,当i变为4,找到最小值1,min(t,p)为3,(意为目前发现3个满足条件的子串:(3-1),(2-1),(4-1)),之后i变为5,由于3不是最值,故t,p,min(t,p)都没变,但此时min(t,p)的意思为找到新的3个满足条件的子串(可以理解为原来找到的子串与不是最值得数合并演变而来的,分别是:(3-3),(2-3),(4-3));到这就基本明白这算式的巧妙之处了;甚是惊讶有木有?所以就能ac了。

猜你喜欢

转载自www.cnblogs.com/wwq-19990526/p/9301053.html