• #QBXT2020 3月DP营 Day2下午


    数位DP

    例题

    求闭区间[l,r]之间有多少个数,用数位DP

    定义一个枚举上限x,f[i][j],表示一位一位枚举数字,枚举到了第i位,同时记录这个数是大于还是小于上限x。

    f[k+1][1] = 1;
    for(int i = k+1;i >= 2; i--){
        for(int j = 0;j <= 1; j++){
            for(int r = 0;r <= 9; r++){
                if(j == 1 && r > y[i-1]) continue;
                f[i-1][j && (r == y[i-1])] += f[i][j];
            }
        }
    }
    ans = f[1][0] + f[1][1];
    

    P3

    求在【L,R】中的满足相邻两个数字之差至少为2的数有多少个

    增加一维,记录上一位填的数:f[i][j][k]填到i,j为小于或等于区间,k记录上一位数的情况。

    P4

    求在[l, r]之间的回文数有多少个.

    f[i][j][k]k表示数字的后i为大于/小于/等于x的后i位,k = 0/1/2。

    
    f[i-1][j && (r == y(i-1))][check(r)] += 
    

    P5

    求在【L,R】中的满足各位数字之积为K的数有多少个

    L,R 10^18

    f[i][j][r]从高到低填到i,j表示小于或等于最大值,r表示个位数字之积等于k(r = 0/1)。但是复杂度太高。

    f[i][j][a][b][c][d],代表枚举到第i个数,小于/等于,2、3、5、7分别出现了几次。

    另特殊处理前导0、非前导0的情况。

    f[i-1][j && (r == y[i-1])][a + (r == a)][b + (r == b)][c + (r == c)][d + (r == d)] += f[i][j][a][b][c][d]
    

    现场yy一道题

    已知:所有的(x_i in [l,r]),求

    [f(x) = |x_1 - x_2| + |x_2 - x_3| + |x_3 - x_4|…… +|x_{n-1} - x_n| ]

    的最值

    f[i][j][k][p] 表示枚举到i位,大于l,小于r,上一位为p的最值(我也忘了是最大还是最小)。

    f[i-1][j && (r == y[i-1])][k && (r == x[i-1])][r] += f[i][j][k][p];
    

    博弈DP

    f[i][j][k]放了i行,有j列有0个炮,有k列有1个炮

    f[i+1][j][k] += f[i][j][k] // 放0个炮的情况
    f[i+1][j-1][k+1] += f[i][j][k] //放了1个炮的个数(本来有0个)
    f[i+1][j][k-1] += f[i][j][k] //放了1个炮的个数(本来有1个)
    //放两个炮的个数:
    f[i+1][j-2][k+2] += f[i][j][k]//两个都放到0上
    f[i+1][j][k-2] += f[i][j][k]//两个都放到1上
    f[i+1][j-1][k] += f[i][j][k]//一个0一个1
    

    排列DP

    有一个1-n的排列,满足某个条件的排列有多少种?

    举例子:1-n的排列中,逆序对数量为偶的佩列有多少个。

    1-i的排列插入i+1可以得到i+1的排列。

    f[i][j]已经把1-i放进排列,形成j个排列的方案数。(也可以把j改成0或1)

    f[1][0] = 1;
    for(int i = 1;i < n; i++)
        for(int j = 0;j <= 1; j++){
            for(int k = 0;k <= i; k++){
                f[i+1][(j+i-k) % 2] += f[i][j];
            }
        }
    

    P14

    对于一个序列,定义其“激动值”为序列中严格大于前面所有数的元素的个数。比如, {1,1,5,6,5}的激动值为3。 给定n个数p1,p2...pn ,求这n个数的所有排列中,激动值不超过k的个数。1≤k≤n≤200;1≤pi≤200

    f[i][j]表示n-i的数全部插入了,此时的激动值为j的排列数。把正着插改成倒着插,问题就解决了。

    YY

    现在有一个1-n的排列,问最长上升子序列长度不超过2的排列有多少个。

    从小到大插,要保证最长上升子序列长度小于等于二。如果此时的子序列等于1或等于2。等于1的话就是插入到最前面。如果把 i+1 插入到序列中,就只能有插入到最前面或者最前面的上升子序列的前面。

    f[i][j]插入了1-i个数,最靠前可以插到第j个数。

  • 相关阅读:
    .net 项目中cookie丢失解决办法
    .net core 时间格式转换
    .net core 分布式性能计数器的实现
    Netty实现原理浅析
    DotNetty项目基本了解和介绍
    xml解析
    StackExchange.Redis性能调优
    C#string转换为Datetime
    C# SocketAsyncEventArgs类
    Des 加密cbc模式 padding
  • 原文地址:https://www.cnblogs.com/Cao-Yucong/p/12595278.html
Copyright © 2020-2023  润新知