欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

牛客练习赛 71 C - 数学考试 ( dp 前缀优化 )

程序员文章站 2022-03-24 19:41:45
链接: C - 数学考试题意 :给出 m 个限制 , 每个限制为前 p 个数不能为 1 - p 的排列 , 求满足条件的1 - n 的排列个数。思路:1 . 考虑一下这个限制 , 前 p 个数不能为 1 - p 的排列 就等价于前 p 个数的最大值不能是 p , 所以可以考虑用 dp[ i ][ j ] 表示前 i 个数的最大值是 j ,限制就可以表示为 dp[ p ][ p ] = 0,接下来就转移就好了。2 . 因为这里的一个状态可以由多个状态转移过来 , 例如 dp[ i ][ j ]...

链接: C - 数学考试

牛客练习赛 71 C - 数学考试 ( dp 前缀优化  )
题意 :
给出 m 个限制 , 每个限制为前 p 个数不能为 1 - p 的排列 , 求满足条件的1 - n 的排列个数。

思路:

  1. 考虑一下这个限制 , 前 p 个数不能为 1 - p 的排列 就等价于前 p 个数的最大值不能是 p , 所以可以考虑用 dp[ i ][ j ] 表示前 i 个数的最大值是 j ,限制就可以表示为 dp[ p ][ p ] = 0,接下来就转移就好了。
  2. 因为这里的一个状态可以由多个状态转移过来 , 例如 dp[ i ][ j ] , 可以由 dp[i - 1] [i - 1] ~ dp[ i -1 ][ j ] 的和转移 , 这里可以用前缀和优化 , 就可以降低一维复杂度,这里还要注意 , 由dp[i-1][j] 转移时 这一位有 i - j + 1 种选择 ,所以这一位还要乘 (i - j + 1 ) .
    代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<stack>
#include<set>
#define iss ios::sync_with_stdio(false)
using namespace std;
typedef long long ll;
using namespace std;
typedef long long ll;
const int maxn=2e3+7;
const int mod=20000311;
ll dp[maxn][maxn],pre[maxn][maxn];
int a[maxn],n,m,vis[maxn];
int main (){
  scanf("%d%d",&n,&m);
  for(int i = 1; i <= m; i ++){
      scanf("%d",&a[i]);
      vis[a[i]] = 1;
  }
  if(vis[1] == 1) dp[1][1] = pre[1][1] = 0;
  else dp[1][1] = pre[1][1] = 1;
  for(int i = 2; i <= n; i ++){
      dp[1][i] = 1;
      pre[1][i] = (pre[1][i-1] + dp[1][i]) % mod; 
  }
  for(int i = 2; i <= n; i ++){
      for(int j = i ; j <= n; j ++){
          if(i == j && vis[i] == 1){
              dp[i][i] = 0;
              continue;
          }
          dp[i][j] = (dp[i][j] + pre[i-1][j - 1] - pre[i-1][i - 2] +dp[i - 1][j] * (j - i + 1) + mod) % mod;
          pre[i][j] = (pre[i][j-1] + dp[i][j]) % mod; 
      }
  }
  printf ("%lld\n",dp[n][n]);






   
}

本文地址:https://blog.csdn.net/hddddh/article/details/108990931

相关标签: dp