zoukankan      html  css  js  c++  java
  • 【JZOJ1857】最大值【dp】

    题目大意:

    题目链接:
    JZOJ:https://jzoj.net/senior/#main/show/1857
    学校局域网:http://10.156.31.134/contestnew.aspx?cid=91

    求在1m1sim m中选出nn个(可重复)最长严格上升子序列为p+1p+1的方案数。


    思路:

    由于TT比较大,考虑先预处理。
    f[i][j][k]f[i][j][k]表示前ii个数字,第ii个数字为jj,最长上升子序列长度为kk的方案数。
    显然需要枚举一个ll,表示第i1i-1位选择的数字。
    如果此次选择的数字是最长上升子序列的最后一位(也就是jj),那么第i1i-1位就可能是1j11sim j-1的任意一位。所以有
    f[i][j][k]+=f[i1][l][k1]f[i][j][k]+=f[i-1][l][k-1]
    如果此次选择的数字不是最长上升子序列的最后一位,那么在1i11sim i-1中最大值也是jj,这次选择的数字是在1j1sim j中的任意一个数字,那么就有
    f[i][j][k]+=f[i1][j][k]×jf[i][j][k]+=f[i-1][j][k] imes j
    但是这样的时间复杂度是O(n2k2)O(n^2k^2)的。
    考虑把枚举的ll去掉。
    由于我们要求
    l=1j1f[i1][k][k1]sum^{j-1}_{l=1}f[i-1][k][k-1]
    所以我们可以考虑使用前缀和优化。
    g[i][j][k]=l=1jf[i][j][k]g[i][j][k]=sum^{j}_{l=1}f[i][j][k],那么第一条方程就变成了
    f[i][j][k]+=g[i1][j1][k1]f[i][j][k]+=g[i-1][j-1][k-1]
    这样的时间复杂度就是O(n2k)O(n^2k)的了。
    接下来TT次询问,每次枚举一下最长上升子序列的最后一位是几,然后取最优输出即可。


    代码:

    #include <cstdio>
    using namespace std;
    typedef long long ll;
    
    const int MOD=1e9+7,N=100,M=300;
    ll f[N+10][M+10][N+10],g[N+10][M+10][N+10],ans;
    int T,n,m,p;
    
    int main()
    {
    	scanf("%d",&T);
    	for (int i=1;i<=M;i++)
    		f[1][i][1]=1,g[1][i][1]=i;
    	for (int i=2;i<=N;i++)
    		for (int j=1;j<=M;j++)
    			for (int k=1;k<=i;k++)
    			{
    				f[i][j][k]=(g[i-1][j-1][k-1]+f[i-1][j][k]*(ll)j)%MOD;
    				g[i][j][k]=(f[i][j][k]+g[i][j-1][k])%MOD;
    			}
    	while (T--)
    	{
    		scanf("%d%d%d",&n,&m,&p);
    		ans=0;
    		for (int i=p+1;i<=m;i++)
    			ans=(ans+f[n][i][p+1])%MOD;
    		printf("%lld
    ",ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    实例下载
    js跳转
    navicat怎么导出和导入数据表
    navicate怎么用sql语句插入一条语句
    svn提交时出现很多乱文件怎么解决
    随机显示星星(点击可删除)
    html节点属性操作
    利用节点更改table内容
    TreeView添加treeView1_NodeMouseClick----多么痛的领悟。。。
    IP addresses in C#
  • 原文地址:https://www.cnblogs.com/hello-tomorrow/p/11998246.html
Copyright © 2011-2022 走看看