NEUQ-ACM 必做题 week4

B3637 最长上升子序列

1.如图,以最后的元素4为例,大于a[1]则可接更新ans为1,又大于a[2]则可接更新ans为2,以此类推,最后大于a[5]可接则更新ans为3,最后加上自身为4

n123456
an​124134
f(n)123134
#include <bits/stdc++.h>
using namespace std;
int a[5000], ans[5000], n;
int main(){
    cin >> n;
    for(int i = 0; i < n; i++){
        cin >> a[i];
    }
    ans[0] = 1;
    for(int i = 1; i < n; i++){
        int maxx = 0;
        for(int j = 0; j < i; j++){ //遍历自身前面所有数
            if(a[j] < a[i]) maxx = max(maxx, ans[j]); //,若大于a[j]说明能接在后面组成新的子序列,比较最长子序列数,更新
        }
        ans[i] = maxx + 1; //加上自身的数字
    }
    sort(ans, ans + n); //升序排列
    cout << ans[n - 1];
    return 0;
}

P1115 最大子段和

1.思路即为实时比较最大值与当前累加值

#include <bits/stdc++.h>
using namespace std;

const int maxn = 2e5 + 5;

int main()
{
    int n;
    int a[maxn];
    int sum, ans;
    cin >> n;
    sum = 0;
    for (int i = 0; i < n; i++)
    {
        cin >> a[i];
        if (!i)
        {
            ans = a[0]; //初始化,将a[0]赋给ans
        }
        sum += a[i]; // 累加a[i]
        ans = max(ans, sum); //实时比较最大值与当前累加值sum
        if (sum < 0) //如sum小于0,说明a[i]没有贡献,即加了负数还变小了
        {
            sum = 0; //则不如清零,从下一个数重新开始累加
        }
    }
    cout << ans << endl;
    return 0;
}

P8707 [蓝桥杯 2020 省 AB1] 走方格

1满足递归公式a[i][j]=a[i-1][j]+a[i][j-1]

#include <bits/stdc++.h>
using namespace std;
int n,m,a[100][100];
int main(){
	cin>>n>>m;
	a[1][1]=1;
	for(int i=1;i<=n;i++){ 
		for (int j=1;j<=m;j++){
			if((i%2==1||j%2==1) && (i!=1|| j!=1) ){ //坐标不都为偶数且不在a[1][1]原点处
				a[i][j]=a[i-1][j]+a[i][j-1];
			}
		}
	}
	cout<<a[n][m];
	return 0;
}

P1216 [USACO1.5] [IOI1994]数字三角形 Number Triangles

1.要求求和最大的一条分支,可以从倒着看,最下面大数加入上一行,以此类推

#include <bits/stdc++.h>
using namespace std;
int n,a[1010][1010];
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=i;j++){
			cin>>a[i][j];
		}
	}
	for (int i=n-1;i>0;i--){ //从倒数第二行开始往上运算
		for(int j=1;j<=i;j++){
			a[i][j]+=max(a[i+1][j],a[i+1][j+1]); //比较左右分支大小,加上大者更新
		}
	}
	cout<<a[1][1];
	return 0;
}

P1020 [NOIP1999 普及组] 导弹拦截

1.循环时间复杂为n,二分时间复杂度为logn,总时间复杂度为O(nlogn)

2.f[i]表示第i套拦截系统最低拦截高度

#include <bits/stdc++.h>
using namespace std;
int n,a[100005],dp[100005],ans=1,p;
int f[100005],cnt=1;
int main(){
	while(cin>>a[++n]); n--;
	dp[1]=a[1];f[1]=a[1];
	for (int i=2;i<=n;i++){ 
		if(dp[ans]>=a[i]) dp[++ans]=a[i]; //求最长降序子数列长度ans
		else {   //a[i]比末尾小直接接入,长度ans加一
			p=upper_bound(dp+1,dp+1+ans,a[i],greater<int>())-dp; //替换
			dp[p]=a[i];
		} 
		
		if(f[cnt]<a[i]) f[++cnt]=a[i]; //求降序子数列个数cnt
		else{   //如大于子数列的头,则需要新开一个子数列,cnt加一
			p=lower_bound(f+1,f+1+cnt,a[i])-f;
			f[p]=a[i];
		}
	}
	cout<<ans<<endl<<cnt<<endl;
	return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值