#Hello 2020

Hello 2020

B New Year and Ascent Sequence

  • 题意:一个数字序列 S 中如果存在\(S_{i}<S_{j} (i<j)\),就说它有“ ascent ” 。在N组数字序列中两两匹配,看有多少组序列组合存在“ ascent ” 。

  • 分析:

    • 两两组合有n2种情况
    • 先不考虑组合中某一序列本身有“ ascent ”的情况。这样当我们处理序列S1时,只要其他序列中有比S1序列的最小值大的数,他们就能构成S1+Si的序列,这个序列满足条件。方便判断,只要Si序列中最大值大于S1序列的最小值就行。
    • 所以我们清楚了要记录所有序列的最大值,最小值。然后维护n个序列最大值中大于当前序列最小值的个数,这也就是当前判断的序列对结果的贡献。见代码。
    • 考虑某序列自身就有“ ascent ”的情况。那它和其他任何序列都可以组合。对于特殊情况应该想到要么对特例进行特殊处理。但在这道题中这么做有点麻烦。还要想到能不能让特殊情况适合一般的情况的解法中。分析后发现,一个序列和其他任何序列都可以组合满足条件。那么它就不受最大值最小值影响。我们把它的最小值改为最小的一个值,最大值改为最大的一个值。这样其他序列的最小值一定比他的最大值小,其他序列可以和他组合。它的最小值一定比其他序列的最大值小,它可以和其他序列组合。这样就将做法统一了。
    • 注意: 特殊情况的最大值最小值不要设为其他序列最值边界值.
  • 代码:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int MA=1e6+15;
    const int MB=1e5+5;
    const int INF=1e9+7;
    
    ll n,l;
    ll minn[MB],maxx[MB]; //记录每个序列最小值,最大值
    ll dmax[MA];     //
    ll ans=0,ax;
    int flag[MB];    //自身是否满足
    
    int main()
    {
        scanf("%lld",&n);
        for(int i=1;i<=n;++i){
            scanf("%lld",&l);
            minn[i]=INF;
            maxx[i]=0;
            for(int j=1;j<=l;++j){
                scanf("%lld",&ax);
                if(ax>minn[i])flag[i]=1;
                minn[i]=min(minn[i],ax);
                maxx[i]=max(maxx[i],ax);
            }
            minn[i]=minn[i]+1;  //调整最值区间
            maxx[i]=maxx[i]+1;
            if(flag[i]){        //如果序列本身满足条件,修改最值
                minn[i]=0;
                maxx[i]=1e6+5;
            }
            dmax[maxx[i]]++;
        }
        ll val1=0,val2=0;
        for(int i=1e6+10;i>=0;--i){
            val2=dmax[i];
            dmax[i]=val1;
            val1+=val2;
        }
        for(int i=1;i<=n;++i){
            ans+=dmax[minn[i]];
        }
        printf("%lld\n",ans);
        return 0;
    }
    
posted @ 2020-01-07 09:16  A_sc  阅读(134)  评论(0编辑  收藏  举报