• CF597C Solution


    题目链接

    题解

    容易看出此题为dp问题,利用LIS的思想可设计出如下\(O(n^2k)\)的算法。

    状态:\(dp[i][j]\)表示以\(a_i\)为结尾、长度为\(j\)的上升子序列个数。

    初始值:\(dp[i][1]=1,dp[0][j]=0\quad(1\le i\le n,1\le j\le k)\)

    转移方程:\(dp[i][j]=\sum\limits_{p=1}^{i-1} dp[p][j-1]\quad (1\le i\le n,2\le j\le min(i,k),a_p<a_i)\)

    答案:\(ans=\sum\limits_{i=k}^ndp[i][k]\)

    其中转移方程仅为一个前缀和,可以想到建一颗\(k\)维的树状数组存储\(dp\)值,每次查询并更新即可在\(O(logn)\)的时间中完成转移。

    AC代码

    #include<bits/stdc++.h>
    #define int long long
    #define lowb(x) x&(-x)
    using namespace std;
    const int N=1e5+10,K=15;
    int a[N],dp[N][K],t[N][K],n; //t[][j]:dp[][j]所对树状数组
    int query(int x,int k)
    {
    	int ans=0;
    	while(x) {ans+=t[x][k]; x-=lowb(x);}
    	return ans;
    }
    void add(int x,int d,int k)
    {
    	while(x<=n) {t[x][k]+=d; x+=lowb(x);}
    }
    signed main()
    {
    	int k,ans=0;
    	scanf("%lld%lld",&n,&k); k++;
    	for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
    	for(int i=1;i<=n;i++)
    	{
    		dp[i][1]=1; add(a[i],1,1);
    		for(int j=2;j<=min(i,k);j++) 
    		{
    			dp[i][j]=query(a[i]-1,j-1);
    			add(a[i],dp[i][j],j);
    		}
    	}
    	for(int i=k;i<=n;i++) ans+=dp[i][k];
    	printf("%lld",ans);
    	return 0;
    }
    
  • 相关阅读:
    基于Python的接口测试框架
    接口自动化之Postman+Newman
    UIAutomator定位Android控件的方法
    HTTP接口功能自动化测试入门
    前端基础:HTML标签(上)
    Python 面向对象进阶
    Python 断言和异常
    Linux 文件上传Linux服务器
    Python 运算符
    Python 基本数据类型
  • 原文地址:https://www.cnblogs.com/violetholmes/p/14385942.html
Copyright © 2020-2023  润新知