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\n",dp[n][n]);
55     return 0;
56 }
View Code

 

posted @ 2020-11-09 11:34  DeepJay  阅读(152)  评论(0编辑  收藏  举报