首页 > 其他分享 >小苯的逆序对

小苯的逆序对

时间:2024-02-16 23:14:54浏览次数:15  
标签:小苯 gcd 示例 int leq 逆序

小苯的逆序对

题目描述

小苯有一个长度为 $n$ 的排列 $p$。他很想知道这个排列中有多少个逆序对满足互素。

形式化的,有多少个满足 $(i<j)$ 且 $(a_i > a_j)$ 且 $gcd(a_i, a_j) = 1$ 的 $(i, j)$ 对。

输入描述:

输入包含两行。

第一行一个正整数 $n(1 \leq n \leq 2\times 10^5)$。表示排列的长度。

第二行 $n$ 个正整数 $p_i (1 \leq p_i \leq n)$ 表示排列 $p$,保证 $1$ 到 $n$ 的每个正整数出现且恰好仅出现一次。

输出描述:

输出包含一行一个整数,表示排列 $p$ 的互素逆序对个数。

示例1

输入

5
5 4 3 2 1

输出

9

示例2

输入

8
1 3 8 7 2 4 6 5

输出

8

示例3

输入

2
1 2

输出

0

备注:

其中 $gcd(x, y)$ 表示 $x, y$ 的最大公因数,例如 $gcd(12, 16) = 4, gcd(1, 4) = 1$。

 

解题思路

  D. Counting Rhyme 的变形。现在变成求满足 $\gcd(a_i, a_j) = 1$ 的逆序对 $(a_i, a_j), \, a_i > a_j, \, i < j$ 的数量。

  定义 $f_i$ 表示 $\gcd$ 恰好等于 $i$ 的逆序对的数量,先求出所有 $\gcd$ 是 $i$ 的倍数的逆序对的数量,记作 $s$。做法是先把 $a$ 中所有是 $i$ 的倍数的元素按原本顺序选出来,然后对选出来的元素用树状数组求逆序对数量。最后根据容斥的思想,有 $f_i = s - f_{2i} - f_{3i} - \cdots - f_{\left\lfloor \frac{n}{i} \right\rfloor \cdot i}$。倒叙枚举依次求出 $f_i$ 即可。

  最后答案就是 $f_1$。

  AC 代码如下,时间复杂度为 $O(n \log{n})$:

#include <bits/stdc++.h>
using namespace std;

typedef long long LL;

const int N = 2e5 + 10;

int n;
vector<int> g[N];
LL f[N];
int tr[N];

int lowbit(int x) {
    return x & -x;
}

void add(int x, int c) {
    for (int i = x; i <= n; i += lowbit(i)) {
        tr[i] += c;
    }
}

int query(int x) {
    int ret = 0;
    for (int i = x; i; i -= lowbit(i)) {
        ret += tr[i];
    }
    return ret;
}

int main() {
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) {
        int x;
        scanf("%d", &x);
        for (int j = 1; j * j <= x; j++) {
            if (x % j == 0) {
                g[j].push_back(x);
                if (x / j != j) g[x / j].push_back(x);
            }
        }
    }
    for (int i = n; i; i--) {
        LL s = 0;
        for (int j = 0; j < g[i].size(); j++) {
            s += j - query(g[i][j]);
            add(g[i][j], 1);
        }
        for (int j = i + i; j <= n; j += i) {
            s -= f[j];
        }
        f[i] = s;
        for (int j = 0; j < g[i].size(); j++) {
            add(g[i][j], -1);
        }
    }
    printf("%lld", f[1]);
    
    return 0;
}

 

参考资料

  题解 | #牛客小白月赛87 #:https://blog.nowcoder.net/n/2804f9f3cb1e4590b1d97bef99b8f28f?

标签:小苯,gcd,示例,int,leq,逆序
From: https://www.cnblogs.com/onlyblues/p/18017600

相关文章

  • P3157 [CQOI2011] 动态逆序对 题解
    题目链接:动态逆序对常见经典题,理解一个数对逆序对贡献计算即可。对于一个数而言,它在一个序列中的逆序对有两部分贡献,一部分为前面比它严格大的数,另一部分为后面比它严格小的数,有道二莫题也是基于此去考虑的。考虑最开始知道了总逆序数,每次删除一个数逆序数会减少两部分值,显然就......
  • 权值树状数组例题——逆序对
    目录问题引入思路一览具体情况code部分补充问题引入(洛谷P1908)[https://www.luogu.com.cn/problem/P1908],简单来说就是给一个数列,求出逆序对的数量思路一览BF做法:遍历数组中的每一个数,对于每一个数,再次遍历前面的数,时间复杂度是n2归并排序:这个...,不太了解,以后明白了再填坑......
  • 逆序对/归并排序
    逆序对定义:对于给定的一段正整数序列,逆序对就是序列中$a_i>a_j$且$i<j$的有序对。P1908逆序对-洛谷|计算机科学教育新生态(luogu.com.cn)#include<bits/stdc++.h>#defineintlonglongusingnamespacestd;constintN=2e6+10;intn,m,a[N],c[N],res,num;void......
  • 逆序句子,但单词顺序不变
    如,输入:Ilikecoding!输出:coding!likeI#define_CRT_SECURE_NO_WARNINGS1#include<stdio.h>#include<assert.h>#include<string.h>voidReverse_arr(char*left,char*right){ assert(left); assert(right); chartem=0; while(le......
  • 一道逆序对题
    CF1915Fhttps://codeforces.com/contest/1915/problem/F先了解什么是逆序对https://www.luogu.com.cn/problem/P1908即i<j但a[i]>a[j]的数对。求解的方法:树状数组求解。树状数组维护的其实就是一个区间内比他大并且比他先出现的值,每次查询的范围就是在原数组的下标之前......
  • 对于 EI K 逆序对排列计数的另一种自然求和方法的理解
    有一个简单的\(O(n^3)\)DP,考虑\(f_{x+1,k}=\sum_{j=0}^{x}f_{x,k-j}\),利用前缀和优化即可。考虑这实际上是\(f_{x+1}(k)=f_x(k)*\frac{1-k^{x+1}}{1-k}\),于是答案实际上为:\[[x^k]f(x)=\prod_{i=1}^n\frac{1-x^i}{1-x}\]接下来的方法来自......
  • 输入一个整数,将这个整数以字符串的形式逆序输出 程序不考虑负数的情况,若数字含有0,则逆
    描述输入一个整数,将这个整数以字符串的形式逆序输出程序不考虑负数的情况,若数字含有0,则逆序形式也含有0,如输入为100,则输出为001数据范围:0\len\le2^{30}-1\0≤n≤230−1输入描述:输入一个int整数输出描述:将这个整数以字符串的形式逆序输出点击查看代码#include<i......
  • 设计一个函数实现字符串的逆序,并且不可以使用库函数
    #define_CRT_SECURE_NO_WARNINGS1#include<stdio.h>voidreverse_string(chararr[],intsz){ intleft=0; intright=sz-1; while(arr[left]<arr[right]) { inttmp=arr[left]; arr[left]=arr[right]; arr[right]=tmp; left++; ......
  • C练习——字符串逆序
    将“abcdefg”逆序注意题意是将字符串逆序,会对字符串本身进行操作,而不是单纯逆序打印方法一:非递归#include<stdio.h>#include<string.h>//将“abcdefg”逆序//注意题意是将字符串逆序,会对字符串本身进行操作,而不是单纯逆序打印voidreverse(chararr[]){intsz......
  • 逆序对——权值树状数组+离散化
    给定一个长度为n的整数数列,请你计算数列中的逆序对的数量。每个数字不超过1e9。intn,m;inta[N];inttr[N];vector<int>lan;intlowbit(intx){ returnx&(-x);}voiddiscrete(){sort(lan.begin(),lan.end());//排序lan.erase(unique(lan.begin(),l......