• BZOJ 2699: 更新 (DP)


    题目

    对于一个数列A[1…N],一种寻找最大值的方法是:依次枚举A[2]到A[N],如果A[i]比当前的A[1]值要大,那么就令A[1]=A[i],最后A[1]为所求最大值。假设所有数都在范围[1, K]内,按上面的步骤执行,有多少个长度N的数列满足A[1]被更新的次数恰好为P呢?
    N,P<=150,K<=300

    题解

    感觉数据组数有点多,其实可以直接预处理出所有答案。

    定义f[i][j][k]f[i][j][k]表示长度为ii,用jle j的数,形成的被更新kk次的数列方案数。

    这里把第一个数出现也看作更新了一次。

    分类转移:

    • jj第一次出现,方案为:f[i1][j1][k1]f[i-1][j-1][k-1]
    • 1j1 o j中任意值,方案为:j(f[i1][j][k]f[i1][j1][k])jcdot(f[i-1][j][k]-f[i-1][j-1][k]),这里前缀和相减,是需要之前的最大值恰好为jj,这样才能不重不漏。
    • 再加上没有用到最大值jj的方案:f[i][j1][k]f[i][j-1][k],也就是做个前缀和。

    CODE

    #include <bits/stdc++.h>
    using namespace std;
    char cb[1<<18],*cs,*ct;
    #define getc() (cs==ct&&(ct=(cs=cb)+fread(cb,1,1<<18,stdin),cs==ct)?0:*cs++)
    inline void rd(int &x) {
    	x = 0; char ch; while(!isdigit(ch=getc()));
    	do x=x*10+ch-'0'; while(isdigit(ch=getc()));
    }
    const int mod = 1e9 + 7;
    const int MAXN = 150;
    const int MAXM = 300; 
    int n, k, p, f[MAXN+5][MAXM+5][MAXN+5];
    int main () {
    	for(int i = 0; i <= MAXM; ++i) f[0][i][0] = 1;
    	for(int i = 1; i <= MAXN; ++i)
    		for(int j = 1; j <= MAXM; ++j)
    			for(int k = 1; k <= MAXN; ++k)
    				f[i][j][k] = (f[i-1][j-1][k-1] + 1ll*j*(f[i-1][j][k]-f[i-1][j-1][k]+mod)%mod + f[i][j-1][k]) % mod;
    	int T; rd(T); while(T--) rd(n), rd(k), rd(p), printf("%d
    ", f[n][k][p+1]);
    }
    
  • 相关阅读:
    异常处理 Exception
    C#使用SQLite出错:无法加载 DLL“SQLite.Interop.dll”,找不到指定的模块
    NullableKey:解决Dictionary中键不能为null的问题 zt
    STSdb
    C# 如何获取某个类型或类型实例对象的大小
    CORREL
    C# 深复制
    mysql数据库创建函数过程
    mysql 数据库怎样快速的复制表以及表中的数据
    代码优化(一)
  • 原文地址:https://www.cnblogs.com/Orz-IE/p/12039211.html
Copyright © 2020-2023  润新知