• 牛客小白月赛 61 E 排队


     题目大意:

            n个数,共有n!种排列方式,记Pi(a)表示序列a的第i种排队方式,cnt(Pi(a))表示P(i)的逆序对个数,PLMM想知道这n!种排列方式共有多少对逆序对

            给定一个 nnn 个数,在所有排列顺序中每种排列的分别的逆序对总数总数是多少

    思路:

            对于互不相等的两数 (a,b),满足 a>b,显然 (a,b)成为逆序对,当且仅当a出现在b之前。所以我们注意到:在 n!次排列下,要么 a 在 b 前面,要么 b 在 a 前面,且两种情况出现的概率都为 1/2​。所以我们对于互不相同的一组 (a,b),计算 (a,b) 的所有排列情况并乘上 1/2即可。

            具体如何计算(a,b)对答案的贡献呢?

            

    1. 对于 a,在未确定位置的 n 个数中它的摆放可以是 n 种
    2. 对于b,在未确定位置的n-1个数种它的摆放可以是n-1种
    3. 所以a,b可以放置的总方案数位n*(n-1),但是需要除以二,因为我们只要大数在前
    4. 剩下的n-2个数,全排列即可(n-2)! 

          由于对于每一个不同的对,处理情况都是一样的,所以只需要统计出来有多少不同的对数,最终乘上一个(n)*(n-1)/2*(n-2)!即可

    1. #include
    2. using namespace std;
    3. #define int long long
    4. const int N=1e5+5,mod=1e9+7;
    5. int n,w[N];
    6. int f[N*2];
    7. signed main() {
    8. f[1]=1;
    9. for(int i=2; i<=N; i++) {
    10. f[i]=f[i-1]*i%mod;
    11. }
    12. cin>>n;
    13. for(int i=1; i<=n; i++) {
    14. cin>>w[i];
    15. }
    16. sort(w+1,w+1+n);
    17. if(n==1) {
    18. cout<<0;
    19. } else {
    20. int cnt=0;//记录不同的对数
    21. for(int i=1; i<=n; i++) {
    22. int fid=lower_bound(w+1,w+1+n,w[i])-(w+1);//找到第一个大于等于它的数的下标(0------n-1)
    23. //找到的这个fid就是前面有多少个小于它的
    24. cnt+=fid;
    25. }
    26. int put=(n*(n-1)/2)%mod*f[n-2]%mod;
    27. //意思是,对于每个对,先找两个位置安排两个数,C(n,2),但是我们只要
    28. //大数在前的情况,所以除2,另外的数随便安排,这样这个对对答案能贡献多少就算出来了
    29. //一个有cnt对,所以把所有对加起来就行了
    30. //因为每个对对答案的贡献是一样的
    31. //所以
    32. cout<<(cnt*put+mod)%mod;
    33. }
    34. return 0;
    35. }

     

  • 相关阅读:
    ClickHouse的JOIN算法选择逻辑以及auto选项
    【前端】CSS(3) —— CSS的盒模型与弹性布局
    Python之pip命令指定安装源和版本
    数据挖掘技术-绘制直方图
    python专属的Remote Produce Call框架:rpyc
    新的iLeakage攻击从Apple Safari窃取电子邮件和密码
    如何一次性解压多个文件
    3682: 【C3】【递推】台阶问题
    3. 无重复字符的最长子串
    分享一个VXLAN的Underlay配置模板
  • 原文地址:https://blog.csdn.net/qq_64214980/article/details/127938169