做题记录 2021.5.29

昨天做了牛客小白竞赛的题目,发现我果然™是个小白 连小白也不如 。现在把会的题目放一下
在这里插入图片描述
把不严格非递减的序列改成严格非递减的最小代价,很明显,就是要求最大不下降子序列(下简称LIS,尽管它们的意义不完全相同)的长度,并用字符串长度减去这个长度即可

#include <cstdio>
#include <algorithm>
#include <cstring>
const int M=1000001;
using namespace std;
char s[M];

int lis(char *s,int n) {
    if(n==0)    return 0;
    if(n==1)    return 1;
    static int dp[M];
    int res=1;
    fill(dp,dp+n+1,1);
    for(int i=1;i<n;i++) {
        for(int j=0;j<i;j++) {
            if(s[i]>=s[j]) {
                dp[i]=max(dp[i],dp[j]+1);
                res=max(res,dp[i]);
            }
        }
    }
    return res;
}

int main(){
	#ifndef ONLINE_JUDGE
	//freopen("in.txt","r",stdin);
	#endif
    int n;
    scanf("%d",&n);
    getchar();
    scanf("%s",s);
    printf("%d",n-lis(s,n));
    return 0;
}

很显然在这样的数据量下会TLE,所以采用O(nlogn)做法。
比方说一个字符串JAVASCRIPT,它的LIS为6。长度为3的序列中就有JST,AAC,CPT,IPT等等符合题意,那么哪个最“好”呢?很显然字符串越“小”,就越容易在后面插入新元素。
换句话说,要让某一长度的合法序列的“大小”尽可能“小”。

具体做法:1.dp[k]的含义变为长度为k的LIS的末尾元素的最小值。既然每个长度都是最小那么这个数组一定是递增的。
2.遍历原数组,如果当前元素不比dp末尾小就直接追加到dp末尾。  否则,找到dp数组中第一个大于当前元素的位置,把它替换为当前元素。这一过程可以用二分查找,故整体时间复杂度为O(nlogn)。

#include <cstdio>
#include <algorithm>
#include <cstring>
const int M=1000001;
using namespace std;
char s[M];

int lis(char *s,int n) {
    if(n==0)    return 0;
    if(n==1)    return 1;
    static char dp[M];
    int res=1;
    fill(dp,dp+n+1,0);
    /*O(N^2)
    for(int i=1;i<n;i++) {
        for(int j=0;j<i;j++) {
            if(s[i]>=s[j]) {
                dp[i]=max(dp[i],dp[j]+1);
                res=max(res,dp[i]);
            }
        }
    }*/
    dp[res]=s[0];
    for(int i=1;i<n;i++) {
        if(s[i]>=dp[res]) {
            //如果有一个不小于当前元素
            dp[++res]=s[i];
        }
        else{
            int j=upper_bound(dp+1,dp+res,s[i])-dp; //找第一个大于dp的元素
            dp[j]=s[i];
        }
    }
    puts(dp+1);
    return res;
}

int main(){
	#ifndef ONLINE_JUDGE
	//freopen("in.txt","r",stdin);
	#endif
    int n;
    scanf("%d",&n);
    getchar();
    scanf("%s",s);
    printf("%d",n-lis(s,n));
    return 0;
}

在这里插入图片描述
很明显的尺取法,可能是给的数据没那么强,所以才侥幸通过→_→

#include <cstdio>
#include <algorithm>
#include <vector>
const int M=10000001;
using namespace std;
int a[M];
int main(){
    int n,x;
    while(~scanf("%d%d",&n,&x)) {
    	//a.push_back(0);
    	int sum=0,l=1,r=1,l_res=l,r_res=r;
    	for(int i=1;i<=n;i++) {
    		//int m;
    		scanf("%d",&a[i]);
    		//a.push_back(m);
    		if(sum<x) {
    			sum+=a[i];
    			r=i;
			}
		}
		int minlen=n,tmp=r-l+1;
		while(r<=n) {
			while(l<r&&sum>=x) {
				sum-=a[l];
				l++;
			}
			if(r-l+1<minlen) {
				l_res=l-1;
				r_res=r;
				minlen=r-l+1;
			}
			while(sum<x&&r<=n) { //要防止越界 
				r++;
				sum+=a[r];
			}
		}
		printf("%d %d\n",l_res,r_res);
	}
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值