zoukankan      html  css  js  c++  java
  • 三元上升子序列

    LuoguP1637

    这道题我看了两种做法

    一:

    对于每个位置分别求出前面小于它的数的个数和后面大于它的数的个数,最后根据乘法原理相乘求和即可

    二:

    这个做法挺厉害的,可以扩展到M元上升子序列

    就还是DP求最长上升子序列个数,不过要用树状数组优化,具体的在代码里有解释

    Code1:

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 const int N = 3e5 + 7;
     4 int n;
     5 int c[N], a[N], b[N], lit[N], big[N];
     6 void add(int x, int v) {
     7     for (int i = x; i <= n; i += i & -i) {
     8         c[i] += v;
     9     }
    10 }
    11 int ask(int x) {
    12     int re = 0;
    13     for (int i = x; i > 0; i -= i & -i) {
    14         re += c[i];
    15     }
    16     return re;
    17 }
    18 int main () {
    19     scanf("%d", &n);
    20     for (int i = 1; i <= n; i++) {
    21         scanf("%d", &a[i]);
    22         b[i] = a[i];
    23     }
    24     sort(b + 1, b + 1 + n);
    25     int m = unique(b + 1, b + 1 + n) - (b + 1);
    26     for (int i = 1; i <= n; i++) {
    27         a[i] = lower_bound(b + 1, b + 1 + m, a[i]) - b;
    28     }
    29     for (int i = 1; i <= n; i++) {
    30         add(a[i], 1);
    31         lit[i] = ask(a[i] - 1);
    32     }
    33     memset(c, 0, sizeof c);
    34     for (int i = n; i >= 1; i--) {
    35         add(a[i], 1);
    36         big[i] = n - i + 1 - ask(a[i]);
    37         //用n-i这个区间(也就是i之后)的长度减去这之中比a[i]小的就是比a[i]大的 
    38     }
    39     long long ans = 0;
    40     for (int i = 1; i <= n; i++) {
    41         ans += lit[i] * big[i];
    42     }
    43     printf("%lld
    ", ans);
    44     return 0;
    45 }
    View Code

    Code2:

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 const int N = 3e5 + 7;
     4 int n;
     5 int c[N], a[N], b[N], f[4][N];
     6 //f[i][j]表示长度为i以a[j]为结尾的上升子序列个数 
     7 void add(int x, int v) {
     8     for (int i = x; i <= n; i += i & -i) {
     9         c[i] += v;
    10     }
    11 }
    12 int ask(int x) {
    13     int re = 0;
    14     for (int i = x; i > 0; i -= i & -i) {
    15         re += c[i];
    16     }
    17     return re;
    18 }
    19 int main () {
    20     scanf("%d", &n);
    21     for (int i = 1; i <= n; i++) {
    22         scanf("%d", &a[i]);
    23         b[i] = a[i];
    24     }
    25     sort(b + 1, b + 1 + n);
    26     int m = unique(b + 1, b + 1 + n) - (b + 1);
    27     for (int i = 1; i <= n; i++) {
    28         f[1][i] = 1;//初始化一下 
    29         a[i] = lower_bound(b + 1, b + 1 + m, a[i]) - b;
    30     }
    31     for (int i = 2; i <= 3; i++) {//本题只需要长度为3 
    32         memset(c, 0, sizeof c);//每个长度都要新的树状数组 
    33         for (int j = 1; j <= n; j++) {
    34             f[i][j] = ask(a[j] - 1);//当前的子序列就是比a[j]小的数 
    35             add(a[j], f[i - 1][j]);//比a[j]大的位置加上不选a[j]时的子序列个数 
    36         }
    37     }
    38     long long ans = 0;
    39     for (int i = 1; i <= n; i++) {
    40         ans += f[3][i];
    41     }
    42     printf("%lld
    ", ans);
    43     return 0;
    44 }
    View Code
  • 相关阅读:
    idea使用配置lombok插件
    微服务框架搭建总结点(一):Springboot整合log4j2日志
    git使用笔记:git commit后,如何撤销commit
    SQL Server中char,varchar,nchar, nvarchar的区别
    SQL插入语句插入自增的主键后,如何获取这个新增的主键值
    Linq分组后,再对分组后的每组进行内部排序,获取每组中的第一条记录
    Flutter 笔记
    gch
    JVM内存观察
    mybatis for 循环 中oracle in 条件后 多余1000条处理
  • 原文地址:https://www.cnblogs.com/Sundial/p/11830601.html
Copyright © 2011-2022 走看看