zoukankan      html  css  js  c++  java
  • SPOJ

    题目链接: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了。

  • 相关阅读:
    Windows照片查看器全屏浏览查看
    Windows调出软键盘
    IE叉事件
    对gridview的小改动
    gridview小把戏
    安全认证(转)
    用数组的方式实现DataTable中的distinct(转)
    TreeView的简单应用
    禁止按钮重复提交
    配置Microsoft Visual SourceSafe 2005的Internet访问(转)
  • 原文地址:https://www.cnblogs.com/wwq-19990526/p/9301053.html
Copyright © 2011-2022 走看看