• 线性DP


    线性DP

    LIS最长上升子序列

    ——Longest increasing subsequence

    转自blog

    暴力:

    为了上升我们肯定要知道我们当前阶段最后一个元素为多少,为了最长我们还要知道当前我们的序列有多长
    (F[i]) 表示以 (A[i]) 为结尾的最长上升子序列的长度,
    为了保证保证元素单调递增我们肯定只能从$ i$ 前面的且末尾元素比$ A[i]$ 小的状态转移过来

    [F[i]=max(f[j]+1)~(0<=j<i,a[j]<a[i]) ]

    边转移转更新答案

    for(int i=1;i<=n;i++){
    	for(int j=1;j<i;j++)
    		if(a[j]<a[i])
    			f[i]=max(f[i],f[j]+1);
    	ans=max(ans,f[i]);
    }	
    

    树状数组优化

    原博客优化1代码是有锅的

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstdlib>
    #include <cstring>
    #include <cmath>
    using namespace std;
    const int N =103,INF=0x7f7f7f7f;
    struct Node{
        int val,id;
    }a[N]; 
    int c[N];
    int n;
    bool cmp(Node a,Node b) {
        return a.val==b.val?a.id<b.id:a.val<b.val;
    }
    void upd(int x,int y) {
        for(;x<=n;x+=x&(-x)) c[x]=max(c[x],y);
    }
    int query(int x) {
        int res=0;
        for(;x;x-=x&(-x)) res=max(res,c[x]);
        return res;
    }
    int main() {
        int ans=0;
        scanf("%d",&n);
        for(int i=1;i<=n;i++) {
            scanf("%d",&a[i].val);
            a[i].id=i;//有时要离散化 
        }
        sort(a+1,a+n+1,cmp);
        for(int i=1;i<=n;i++) {
            int maxx=query(a[i].id);//查询编号小于等于id[i]的LIS最大长度
            upd(a[i].id,++maxx);//把长度+1,再去更新前面的LIS长度
            ans=max(ans,maxx);//更新答案
        }
        printf("%d
    ",ans);
        return 0;
    }
    

    贪心+二分查找优化

    不上升g/下降f子序列

        g[1]=f[1]=a[1];
        for(int i=2;i<=n;i++){
            if(g[now]>=a[i]) g[++now]=a[i];
            else g[upper_bound(g+1,g+now+1,a[i],cmp())-g]=a[i];
            if(f[con]<=a[i])f[++con]=a[i];
            else f[upper_bound(f+1,f+con+1,a[i])-f]=a[i];
        }
    ans=now or con
    

    LCS最长公共子序列

    ——longest common subsequence

    公共子序列和公共子串的区别

    公共子串是指连续的公有字符串,公共子序列是指两个字符串都任意删除0个或多个字符后得到的公有字符串,子序列可以是不连续的。

    举个例子吧,有两个字符串,串A为“1 2 3 4 5 6 7”,串B 为“1 3 4 5 8 7”,很明显,A和B的公共子串为“3 4 5”,A和B的公共子序列可以是 “3 5”,或是“1 3 7”,等等。

    最长公共子串:在两个字符串中找到一个最长的公共子串,要求子串在原串中是连续的。

    最长公共子序列:在两个字符串中找到一个最长的公共子串,不要求子串在原串中是连续的。

    f[i][0]=f[0][i]=0;
    for(int i=1;i<=n;i++)
    	for(int j=1;j<=m;j++){
    		f[i][j]=max(f[i][j],f[i-1][j]);
    		f[i][j]=max(f[i][j],f[i][j-1]);
    		if(a[i]==b[j]) f[i][j]=max(f[i][j],f[i-1][j-1]+1);
    	}
    cout<<f[n][m];
    

    LCIS最长公共上升子序列

    https://www.cnblogs.com/WArobot/p/7479431.html

    cnblogs.com/Howe-Young/p/5082611.html

    题目:

    守望者的逃离

    贪心。。。然鹅我只70pts

    能闪现肯定闪现

    不能闪我讨论了好几种

    放个傻代码记录一下

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    using namespace std;
    int m,s,t;
    int ans;
    bool f;
    int main() {
        scanf("%d%d%d",&m,&s,&t);
        int ans=t,ss=s;
        while(s>0){
            while(m>=10&&t>0){
                if(s<=0) break;
                s-=60,m-=10,t--;
            } 
            while(m>=6&&s>17&&t>=2) {
            	t-=2;s-=60;m=m+4-10;
            	if(s<=0) break;
    		}
            while(m>=2&&s>34&&t>=3){
            	m+=2,t-=3,s-=60;
            	if(s<=0) break;
    		} 
            if(s>=120&&t>=7)  {s-=120;t-=7;}
            while(t>0&&s<120) {
                if(s<=0) break;
                s-=17,t--;
            }
            if(t<=0&&s>0) {f=1;break;}
        } 
        if(f) {
            printf("No
    ");
            printf("%d
    ",ss-s);
        } else {
            printf("Yes
    ");
            printf("%d
    ",ans-t);
        }
        return 0;
    }
    

    题解巧妙地方法是把闪现和跑步分着存距离——谁大就要谁

    然后枚举时间

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    using namespace std;
    int m,s,t;
    int s1,s2;
    bool f;
    int main() {
        scanf("%d%d%d",&m,&s,&t);
        for(int i=1;i<=t;i++) {
        	s1+=17;
        	if(m>=10) {s2+=60,m-=10;}
        	else m+=4;
        	if(s2>s1) s1=s2;
        	if(s1>s) {
        		puts("Yes");
        		printf("%d
    ",i);
        		return 0;
    		} 
    	}
    	puts("No"); 
    	printf("%d
    ",s1);
        return 0;
    }
    

    dp思想也很好理解

    #include <cstdio>
    #include <algorithm>
    using namespace std;
    int dp[300001];
    int main()
    {
        int m, s, t;
        scanf("%d%d%d", &m, &s, &t);
        for (int i = 1; i <= t; i++)
        { 
            if (m >= 10)
                dp[i] = dp[i - 1] + 60, m -= 10; 
            else
                dp[i] = dp[i - 1], m += 4; 
        }
        for (int i = 1; i <= t; i++)
        {
            dp[i] = max(dp[i], dp[i - 1] + 17); 
            if (dp[i] >= s)
            {
                printf("Yes
    %d", i);
                return 0;
            } 
        }
        printf("No
    %d", dp[t]); 
        return 0;
    }
    

    乌龟棋

    一开始想着开 5 维,当场爆炸,然后又去写了爆搜

    30骗到手

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    using namespace std;
    int n,m;
    int x[355],y[355];
    int ans,res;
    void dfs(int pos) {
    	if(pos==n) {ans=max(ans,res);return;}
    	if(pos>n) return; 
    	for(int i=1;i<=4;i++){
    		if(y[i]==0) continue;
    		pos+=i;y[i]--;res+=x[pos];
    		dfs(pos);
    		res-=x[pos];pos-=i;y[i]++;
    	}
    	return;
    }
    int main(){
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=n;i++)
    		scanf("%d",&x[i]);
    	for(int i=1,u;i<=m;i++){
    		scanf("%d",&u);
    		y[u]++;
    	}
    	dfs(1);
    	printf("%d
    ",x[1]+ans);
    	return 0;
    }
    

    然后刚点开题解就发现4维就可以。。。毕竟题目说最后肯定能到n

    想啊想,终于想到了

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<cmath>
    using namespace std;
    int n,m;
    int x[355],y[355];
    int ans,res;
    int f[41][41][41][41];
    inline void Max(int &x,int y){if(x<y) x=y;}
    int main(){
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=n;i++)
    		scanf("%d",&x[i]);
    	for(int i=1,u;i<=m;i++){
    		scanf("%d",&u);
    		y[u]++;
    	}
    	f[0][0][0][0]=x[1];
    	for(int i=0;i<=y[1];i++) {
    		for(int j=0;j<=y[2];j++) {
    			for(int k=0;k<=y[3];k++) {
    				for(int l=0;l<=y[4];l++) {
    					int add=x[i+j*2+k*3+l*4+1];
    					if(i>0) Max(f[i][j][k][l],f[i-1][j][k][l]+add);
    					if(j>0) Max(f[i][j][k][l],f[i][j-1][k][l]+add);
    					if(k>0) Max(f[i][j][k][l],f[i][j][k-1][l]+add);
    					if(l>0) Max(f[i][j][k][l],f[i][j][k][l-1]+add);
    				}
    			}
    		}
    	}
    	printf("%d
    ",f[y[1]][y[2]][y[3]][y[4]]);
    	return 0;
    }
    
    
  • 相关阅读:
    css样式兼容不同浏览器问题解决办法
    css 中input和select混排对齐问题
    盒模型详解
    css中的width,height,属性与盒模型的关系
    php中将文中关键词高亮显示,快捷方式可以用正则
    数据库面试知识
    ConcurrentHashMap原理分析(1.7与1.8)
    Docker 学习笔记
    秒杀系统架构分析与实战
    spring + redis 实现数据的缓存
  • 原文地址:https://www.cnblogs.com/ke-xin/p/13499712.html
Copyright © 2020-2023  润新知