• cf 1437F.Emotional Fishermen(计数dp)


    题目链接:传送门

    题目思路:

    题目思路参考于博客:&*^*&(

    题目是关于前缀最大值的,那么不妨先将a数组排序,定义dp(i,j) 表示长度为 i 且最大元素为 a的合法排列个数

    根据排序后的单调性,预处理出 posiposi 的值是满足 aj * 2 <= ai 的最大的 j ; 

    所谓合法,即满足下式:(p数组是1-n的排列)

      

    现在考虑dp(i,j)的转移:

      首先排列的最大值为aj ,那么其他 i -1 个项是一定 <= aj / 2 的,且保证合法,

      1)dp(i,j) <- dp(i-1,j) * max( 0 , posj - i + 2 )

       如果是前 i-1 项 的最大元素已经是 aj 了,那么第 i 个位置 能填写的数字个数为 posj - i +2 个(前面有一个aj 和 i-2 个 ak ,k<=posj ,这个位置就只剩下 posj - (i-2) 个数字可填 );

      2)dp(i,j) <- Σdp(i-1,k) ,  k≥1 && k≤posj ;(前缀和优化)

       如果前 i-1 项的最大元素不为aj ,由第 i 个位置 加入 aj 将最大值更新为 aj ,那么前 i-1 项的最大值为 ak , k≥1 && k≤posj

      显然 ,dp(1,i) = 1 ,则将dp(1,i) 作为 初始状态,递推填表即可。 

    代码:

     1 #include<bits/stdc++.h>
     2 #pragma GCC optimize(2)
     3 using namespace std;
     4 typedef long long LL;
     5 typedef unsigned long long uLL;
     6 typedef pair<int,int> pii;
     7 typedef pair<LL,LL> pLL;
     8 typedef pair<double,double> pdd;
     9 const int N=5e3+5;
    10 const int M=5e3+5;
    11 const int inf=1e8;
    12 const LL mod=998244353;
    13 const double eps=1e-8;
    14 const long double pi=acos(-1.0L);
    15 #define ls (i<<1)
    16 #define rs (i<<1|1)
    17 #define fi first
    18 #define se second
    19 #define pb push_back
    20 #define eb emplace_back
    21 #define mk make_pair
    22 #define mem(a,b) memset(a,b,sizeof(a))
    23 LL read()
    24 {
    25     LL x=0,t=1;
    26     char ch;
    27     while(!isdigit(ch=getchar())) if(ch=='-') t=-1;
    28     while(isdigit(ch)){ x=10*x+ch-'0'; ch=getchar(); }
    29     return x*t;
    30 
    31 }
    32 LL a[N],dp[N][N],pos[N],sum[N];
    33 int main()
    34 {
    35     int n=read();
    36     for(int i=1;i<=n;i++) a[i]=read();
    37     sort(a+1,a+n+1);
    38     int l=0;
    39     for(int i=1;i<=n;i++){
    40         while(a[l+1]*2<=a[i]) l++;
    41         pos[i]=l;
    42     }
    43     for(int i=1;i<=n;i++) dp[1][i]=1;
    44     for(int i=2;i<=n;i++)
    45     {
    46         for(int j=1;j<=n;j++) sum[j]=(sum[j-1]+dp[i-1][j])%mod;
    47         for(int j=1;j<=n;j++)
    48         {
    49             dp[i][j]=sum[pos[j]];
    50             dp[i][j]+=dp[i-1][j]*max(0LL,pos[j]-i+2);
    51             dp[i][j]%=mod;
    52         }
    53     }
    54     printf("%lld
    ",dp[n][n]);
    55     return 0;
    56 }
    View Code
  • 相关阅读:
    NCNN优化实时面部关键点检测
    使用 div 标签 contenteditable="true" 实现一个 聊天框,支持 Ctrl + v 粘贴图片
    《精益创业》读书总结
    DATAX使用
    canal增量同步原理以及使用说明
    element rules required 自定义表达式
    JavaScript 数组映射,重新整理
    wangeditor遮挡其他控件
    多个axios按顺序执行
    .NET Core 中基于 IHostedService 实现后台定时任务
  • 原文地址:https://www.cnblogs.com/DeepJay/p/13947715.html
Copyright © 2020-2023  润新知