2019-3-21训练赛总结

dp+二分(最长不降子序列问题)
在这里插入图片描述
题意
题目就是要你求出最长非递减的最长子序列长度
白书(挑战程序设计)中提供两种算法 O ( n 2 ) 和 O ( n l o g n ) O(n^2)和O(nlogn) O(n2)Onlogn解决该问题
第一种算法用到的知识是dp
d p [ i ] 表 示 以 a [ i ] 结 尾 的 最 长 子 序 列 , 更 新 方 式 是 d p [ j ] − > d p [ i − 1 ] ( 即 j 从 1 到 i − 1 ) dp[i]表示以a[i]结尾的最长子序列,更新方式是dp[j]->dp[i-1](即j从1到i-1) dp[i]a[i]dp[j]>dp[i1](j1i1)
i f ( a [ i ] > = a [ j ] ) d p [ i ] = m a x ( d p [ i ] , d p [ j ] + 1 ) if(a[i]>=a[j]) dp[i]=max(dp[i],dp[j]+1) if(a[i]>=a[j])dp[i]=max(dp[i],dp[j]+1)

    max_size=1;
for(int i=1;i<=n;i++){
   dp[i]=1;//单独以a[i]为序列的长度
   for(int j=1;j<i;j++){
   if(a[i]>=a[j]) dp[i]=max(dp[i],dp[j]+1);
   }
}
   max_size=max(max_size,dp[i]);

第二种算法用到的知识是二分+思维
在这里插入图片描述
15 大 于 12 , 进 入 s t a c k 里 面 , 只 要 元 素 大 于 等 于 栈 顶 元 素 就 可 以 让 元 素 入 栈 15大于12,进入stack里面,只要元素大于等于栈顶元素就可以让元素入栈 1512stack
在这里插入图片描述
如 果 15 不 大 于 20 的 话 , 我 们 就 需 要 把 17 换 成 15 , 因 为 如 果 子 序 列 的 长 度 相 同 , 那 么 末 位 置 的 元 素 较 小 的 在 之 后 会 更 加 有 优 势 如果15不大于20的话,我们就需要把17换成15,因为如果子序列的长度相同,那么末位置的元素较小的在之后会更加有优势 15201715

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
const int maxn=1e6+5;
int a[maxn],cnt=0;
int main(){
     int n,k;
     scanf("%d",&n);
     for(int i=1;i<=n;i++){
	scanf("%d",&k);
	if(a[cnt]<=k){
		a[++cnt]=k;
	}
	else{
	a[lower_bound(a+1,a+cnt+1,k)-a]=k;
	}
     }
     if(n-cnt<=1){printf("YES\n");}
     else{
	printf("NO\n");
     }
    return 0;
}

区间dp+前缀和
在这里插入图片描述
题解
s u m 表 示 当 前 前 缀 和 sum表示当前前缀和 sum
如 果 当 前 加 入 的 数 大 于 前 缀 和 + 1 , 那 么 输 出 前 缀 和 + 1 , 否 则 继 续 。 如果当前加入的数大于前缀和+1,那么输出前缀和+1,否则继续。 +1+1
因 为 需 要 表 示 连 续 的 整 数 , 那 么 相 邻 的 数 最 多 只 能 差 1. 因为需要表示连续的整数,那么相邻的数最多只能差1. 1.
如 果 排 序 后 k 前 面 的 数 字 之 和 &lt; k − 1 , 那 么 k − 1 这 个 数 就 无 法 表 示 。 如果排序后k前面的数字之和&lt;k-1,那么k-1这个数就无法表示。 k<k1,k1
再 详 细 的 说 就 是 再详细的说就是
现 在 能 表 示 出 [ 0 , 0 ] 这 个 区 间 , 那 么 对 于 排 序 后 接 下 来 的 数 k , 如 果 k &gt; 1 , 那 么 1 现在能表示出[0,0]这个区间,那么对于排序后接下来的数k,如果k&gt;1,那么1 [0,0]kk>11
这 个 数 就 永 远 也 拼 不 出 来 。 那 么 对 于 之 前 能 拼 出 的 区 间 为 [ 0 , x ] , 加 上 k 之 后 能 拼 出 这个数就永远也拼不出来。那么对于之前能拼出的区间为[0,x],加上k之后能拼出 [0,x]k
的 数 至 少 为 [ k , x + k ] , 必 须 要 求 [ 0 , x ] 这 个 区 间 的 右 端 点 和 [ k , k + x ] 的 左 端 点 连 续 才 能 把 所 有 的数至少为[k,x+k],必须要求[0,x]这个区间的右端点和[k,k+x]的左端点连续才能把所有 [k,x+k],[0,x][k,k+x]
数 都 拼 出 来 , 也 就 是 k &lt; = x + 1 数都拼出来,也就是k&lt;=x+1 k<=x+1

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <set>
using namespace std;
typedef long long ll;
const int maxn=1e5+5;
ll a[maxn],sum[maxn];
int n;
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
	scanf("%d",&a[i]);
    }
    sort(a+1,a+n+1);
    for(int i=1;i<=n;i++){
    	if(a[i]>sum[i-1]+1) {cout<<sum[i-1]+1<<endl;return 0;}
    	sum[i]=sum[i-1]+a[i];
    }
    cout<<sum[n]+1<<endl;
    return 0;
}

优化算法
在这里插入图片描述
直接 O ( n ) + 优 化 O(n)+优化 O(n)+AC

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <set>
using namespace std;
typedef long long ll;
ll cnt=0;
int main(){
	ll n;
	scanf("%lld",&n);
	for(int i=1;i<=n;i++){
		ll num=n/i;
		i=n/num;
		cnt++;
	}
cout<<cnt<<endl;
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值