zoukankan      html  css  js  c++  java
  • DP搬运工2

    DP搬运工2

    题目描述

    给你 (n,K),求有多少个 (1)(n) 的排列,恰好有 (K) 个数 (i(1<i<n)) 满足 (a_{i-1},a_{i+1}) 都小于 (a_i)

    输入格式

    一行两个整数 (n,K)

    输出格式

    一行一个整数 (ans) 表示答案 (mod 998244353)

    样例

    样例输入1

    4 1
    

    样例输出1

    16
    

    样例输入2

    10 3
    

    样例输出2

    1841152
    

    数据范围与提示

    对于 (25\%) 的测试点,(1leqslant n,K leqslant 10)

    对于 (50\%) 的测试点,(1leqslant n,K leqslant 100)

    对于 (100\%) 的测试点,(1leqslant n,K leqslant 2000)

    保证数据有梯度

    分析

    同样的预设型 (dp) ,但是要简单一些。我们这次只需要考虑有几个符合条件即可。所以我们定义 (f[i][j]) 为插入 (i) 的时候,有 (j) 个满足要求的数。我们仍然按照插入位置分情况。

    转移肯定是从 (f[i-1][j]) 转移来,那么我们考虑一下,什么情况下加一个数但是符合要求的数量不变:

    • 1、放到之前符合要求的某一组里,多了一组少了一组,相当于没变化。
    • 2、放到两个端点的时候不变。

    其他情况都是不加的。然后愉快的转移

    代码

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    using namespace std;
    const int maxn = 2e3+10;
    const int mod = 998244353;
    int n,k;
    int f[maxn][maxn];
    int main(){
    	scanf("%d%d",&n,&k);
    	//初始化
    	f[1][0] = 1;
    	f[2][0] = 2;
    	for(int i=3;i<=n;++i){
    		int jl = min(k,i>>1);//最多有i除以2的满足的情况。
    		for(int j=0;j<=jl;++j){//枚举所有的位置
    			if(f[i-1][j] == 0)continue;
    			f[i][j] = (f[i][j] + f[i-1][j] * 1LL * ((j+1) << 1))%mod;//放到之前的某个里或者边界,此时满足条件的不加
    			f[i][j+1] = (f[i][j+1] + f[i-1][j] * 1LL * (i-((j+1) << 1)))%mod;//放到其他地方,满足条件的加一
    		}
    	}
    	printf("%d
    ",f[n][k]);
    	return 0;
    }
    
    $Never Give Up$
  • 相关阅读:
    Android官方数据绑定框架DataBinding*
    Application 使用分析*
    Android HandlerThread与IntentService*
    Android中SQLite应用详解*
    Android开发中,那些让您觉得相见恨晚的方法、类或接口*
    巧用ViewPager 打造不一样的广告轮播切换效果*
    Android-Universal-Image-Loader的缓存处理机制与使用 LruCache 缓存图片*
    Android Volley完全解析*
    Android 蓝牙*
    Android自定义View
  • 原文地址:https://www.cnblogs.com/Vocanda/p/13543021.html
Copyright © 2011-2022 走看看