• 出题人的手环


    题目链接:https://ac.nowcoder.com/acm/contest/358/D

    链接:https://ac.nowcoder.com/acm/contest/358/D
    来源:牛客网

    时间限制:C/C++ 1秒,其他语言2秒
    空间限制:C/C++ 524288K,其他语言1048576K
    64bit IO Format: %lld

    题目描述

    出题人的妹子送了出题人一个手环,这个手环上有 n 个珠子,每个珠子上有一个数。
    有一天,出题人和妹子分手了,想把这个手环从两个珠子间切开,并按顺时针顺序展开成一条链。
    可以发现,这条链一共有 n 种可能性。求这 n 种可能性的逆序对数之积模 1000000007。

    输入描述:

    第一行一个数 n,表示珠子个数。
    接下来一行 n 个数,以顺时针顺序给出每个珠子上的整数

    输出描述:

    一个数,表示答案。
    示例1

    输入

    复制
    4
    1 3 2 3

    输出

    复制
    24

    说明

    一共有 4 种方式:
    1 3 2 3;3 1 3 2;2 3 1 3;3 2 3 1;
    逆序对数分别为 1,3,2,4,积为 24。

    备注:

    n<=200000,-10^9<=珠子上的整数<=10^9。

    个人思路:做到这题的时候,推出了规律,就是下一次可以在前一次的基础上减去小于第一个数的数,加上大于第一个数的数 但问题是怎么求得第一个环有多少个逆序对数,想了许久,发现怎么处理都要n*n 的复杂度,但是明显会
    超时,所以这题写不下去了,之后看题解,都是用树状数组加上离散化的思想来做的,想想也是,只有用树log(n)的复杂度才能满足,但是这题怎么用树状数组呢?
        都知道树状数组是树形结构,可以求区间和 和 单点更新,但是我们这题和区间和有什么关系呢? 我们要求的是逆序对数,也就是一个区间内在一个数后面的数比它小 因为顺序是递增的 逆序就是递减的咯。
        我们怎么求区间内 后面的比它小的数的个数呢? 首先,把每个数在序列中从小到大排第几算出来,相等的话就并列排第几,排第几也就是该数在序列中第几小,然后这个顺序就可以当做树状数组的下标了,
        但是还有一个问题,我们要求的是在这个数后面比它小的数,而不是整个序列中比它小的数,所以按照原始顺序插入的同时计算后面有多少个比它小的,其实就是减去前面有多少个比它大的,这就是答案了。
    具体看代码:
    #include<iostream>
    #include<algorithm>
    using namespace std;
    const int maxn=200000+5;
    const int mod=1000000007;
    typedef long long ll;
    ll n;
    int a[maxn];//a[i]表示 原位置为i的数 在序列中从小到大排第几
    int c[maxn];//树状数组存储结构
    struct Node{
        int v,w;//v代表值 w代表位置
    }node[maxn];
    bool cmp(const Node a,const Node b)
    {
        return a.v<b.v;
    }
    int lowbit(int x)
    {
        return x&(-x);
    }
    void updata(int pos,int v)
    {
        while(pos<=n)
        {
            c[pos]+=v;
            pos+=lowbit(pos);
        }
    }
    int getsum(int pos)//求有多少个数比它小
    {
        int sum=0;
        while(pos>0)
        {
            sum+=c[pos];
            pos-=lowbit(pos);
        }
        return sum;
    }
    int main()
    {
        cin>>n;
        for(int i=1;i<=n;i++)//存储对应的值和所在的位置
        {
            cin>>node[i].v;
            node[i].w=i;
        }
        sort(node+1,node+1+n,cmp);//按大小从小到大排序
        a[node[1].w]=1;//最小的数显然是排第一
        int pos=1;
        for(int i=2;i<=n;i++)//存取每个数按从小到大排序 能排第几
        {
            if(node[i].v==node[i-1].v) a[node[i].w]=pos;//相等的话则为首个数的位置
            else a[node[i].w]=++pos;
        }
        ll ans=0;
        ll re=1;
        for(int i=1;i<=n;i++)
        {
            updata(a[i],1);//插入树状数组
            ans=(ans+(i-getsum(a[i])+mod))%mod;//i是原位置 a[i]是原位置的数所排大小  getsum(a[i])  该大小的数前面有几个数
    
        }
        re=(re*ans)%mod;
        ll ad;
        ll sub;
    
        for(int i=1;i<n;i++)//求出了第一种情况的,接下来就是 每一次在前一次的基础上 减掉小于第一个数的数 加上大于第一个数的数
        {
    
            ad=(n-getsum(a[i]));
            sub=getsum(a[i])-(getsum(a[i])-getsum(a[i]-1));//注意这里是 a[i]-1  而不是 a[i-1]  !!  我就错在这了
            ans=(ans-sub+mod+ad)%mod;
            re=(re*ans)%mod;
        }
    
        cout<<re<<endl;
    }
    当初的梦想实现了吗,事到如今只好放弃吗~
  • 相关阅读:
    构架设计:负载均衡层设计方案(1)——负载场景和解决方式
    ActiveMQ5.14.1+Zookeeper3.4.9高可用伪分布式部署
    TCP同步与异步,长连接与短连接【转载】
    各种加密解密算法的比较和适用场合(转)
    ElasticSearch安装部署,基本配置(Ubuntu14.04)
    OpenResty--mysql,redis 项目中的应用
    mysql慢日志
    MongoDB之Replica Set(复制集复制)
    pycharm的一些设置和快捷键
    jmap
  • 原文地址:https://www.cnblogs.com/caijiaming/p/10294552.html
Copyright © 2020-2023  润新知