zoukankan      html  css  js  c++  java
  • 排列 [计数dp]


    SOLUTIONmathbb{SOLUTION}

    状态:
    F[i,j]i,Ai,AjF[i, j] 表示前 i 项, 递增序列最后一个元素为A_i的方案, 递减序列最后一个元素为A_j的方案
    G[i,j]i,Ai,AjG[i, j] 表示前 i 项, 递减序列最后一个元素为A_i的方案, 递增序列最后一个元素为A_j的方案

    Ask:G[][] ?Ask: 为什么要另外开一个 G[][] 状态 ?
    Answer:,.Answer: 说完转移后,自会提到.

    转移:

    注: 1<=j<i<=N1<=j<i<=N

    1. iii1i-1 同属一个序列,

      1. Ai1<AiA_{i-1}<A_i, F[i,j]  +=  F[i1,j]F[i, j] += F[i-1, j];
      2. Ai1>AiA_{i-1}>A_i, G[i,j]  +=  G[i1,j]G[i, j] += G[i-1, j].

    1. iii1i-1 不同属一个序列,

      1. Aj<AiA_j<A_i, F[i,i1]  +=  G[i1,j]                          (F[j,i1])F[i, i-1] += G[i-1,j] (F[j,i-1])
      2. Aj>AiA_j>A_i, G[i,i1]  +=  F[i1,j]                          (G[j,i1])G[i, i-1] += F[i-1,j] (G[j,i-1])

    2?看到情况2的括号了吗?
    ,G[][]使这些状态在转移时还没有值,所以额外开了 G[][] 来使得转移可行

    至此已经完成了 O(N2)mathcal{O(N^2)} 的算法, 使用树状数组滚动即可优化为O(nlogn)mathcal{O(nlogn)}


    可能会出现 不存在某种序列 的情况, 所以要进行特殊处理, 代码中已用 ## 注释


    CODEmathbb{CODE}

    #include<bits/stdc++.h>
    #define reg register
    
    int read(){
            char c;
            int s = 0, flag = 1;
            while((c=getchar()) && !isdigit(c))
                    if(c == '-'){ flag = -1, c = getchar(); break; }
            while(isdigit(c)) s = s*10 + c-'0', c = getchar();
            return s * flag;
    }
    
    const int maxn = 1500006;
    const int mod = 666623333;
    
    int N;
    int M;
    int A[maxn];
    
    struct Tree{
            int tap[maxn], v[maxn], tim;
            void Modify(int k, int x){
                    while(k <= N){
                            if(tap[k] != tim) tap[k] = tim, v[k] = 0;
                            v[k] += x;
                            if(v[k] >= mod) v[k] -= mod;
                            k += k & -k;
                    }
            }
            int Query(int k){
                    int s = 0;
                    while(k >= 1){
                            if(tap[k] != tim) tap[k] = tim, v[k] = 0;
                            s += v[k];
                            if(s >= mod) s -= mod;
                            k -= k & -k;
                    }
                    return s;
            }
    } Ft, Gt;
    
    int flag_1, flag_2; // 1↑ 2↓
    
    int main(){
            freopen("perm.in", "r", stdin);
            freopen("perm.out", "w", stdout);
            N = read();
            for(reg int i = 1; i <= N; i ++) A[i] = read();
            Ft.Modify(1, 1), Gt.Modify(1, 1);
            flag_1 = flag_2 = 1;			// #
            for(reg int i = 2; i <= N; i ++){
                    int tmp_1 = Ft.Query(N-A[i]+1), tmp_2 = Gt.Query(A[i]);
                    if(A[i-1] < A[i]) flag_1 = 0, Gt.tim ++;	// #
                    else flag_2 = 0, Ft.tim ++;					// #
                    Ft.Modify(N-A[i-1]+1, tmp_2), Gt.Modify(A[i-1], tmp_1);
            }
            printf("%d
    ", (Ft.Query(N)+Gt.Query(N)-flag_1-flag_2)%mod);
            return 0;
    }
    
    
  • 相关阅读:
    第1关:逆序输出数组元素
    Ubuntu配置java环境安装JDK8
    Ubuntu18安装Tomcat服务
    Windows+ubuntu1803双系统安装
    问题 F: 水仙花数(C#)
    问题 A: C#异或运算符的使用
    hdu 2642 Stars 【二维树状数组】
    poj 2352 stars 【树状数组】
    hdu 1698 Just a Hook 【线段树+lazy】
    线段树【单点更新,区间更新,区间查询,最值查询】
  • 原文地址:https://www.cnblogs.com/zbr162/p/11822623.html
Copyright © 2011-2022 走看看