个人题目总结:一步两步、沧海的孤塔-chimera(动态规划、线段树以及二分)

动态规划、线段树以及二分

  • 二分及思维题目
    • 一步两步
      • 题目描述
      • 题目思路及代码
  • 动态规划及线段树题目
    • 沧海的孤塔-chimera
      • 题目描述
      • 题目思路及代码

二分及思维题目

一步两步

题目描述

题目描述

现在有一条数轴,有一只青蛙起始在0号位置,它在第i次可以跳i步,方向可以为数轴正向或反向,现在小青蛙想跳到数轴的正向n号位置,请问最少需要跳几次?如果不能跳到目的地,请输出“NO”,否则输出跳跃次数。

输入

输入一个正整数n表示小青蛙想去的目的地(0 ≤ n ≤ 1e18)。
输出

输出请问最少需要跳几次到达n?如果不能跳到目的地,请输出“NO”,否则输出跳跃次数。

样例输入

4

样例输出
3

提示

第一次反向跳1步,第二次和第三次分别向正向跳2步和3步,最终在位置4。一共跳跃了三次。 

题目思路及代码

思路:
首先青蛙一定能走到目的地 n,假前 i 步正向走直到 sum = 1+2+…+i ≥ n,这时候还需要回退 sum – n 步,只需要在第(sum - n) / 2 的位置选择向负方向走即可。
考虑 sum – n 的奇偶性:

  • 偶数,选择(sum - i) / 2 位置反向,总步数为 i。

  • 奇数,

    • 若 i 为偶数,则 i + 1 为奇数,再多走一步奇偶性改变,选择(sum + i + 1 - n) / 2 位置反向,总步数为 i + 1。
    • 若 i + 1 为偶数,多走一步不会改变奇偶性,则选择在 i + 1 和 i + 2的位置一个正向一个反向,奇偶性发生了改变,总步数为 i + 2。

求解 i 考虑使用二分+等差数列求和公式。

#include
using namespace std;
typedef unsigned long long int ll;
ll n;
ll psum(ll x){
	return x*(x+1)/2;
}
int main(){
	cin>>n;
	ll l=0,r=20000000000;
	while(l<r){
		ll mid=(l+r)>>1;
		if(psum(mid)>=n){
			r=mid;
		}else{
			l=mid+1;
		}
	}
	ll ans=l;
	ll sum=psum(l);
	if((sum-n)&1){
		if(l&1){
			cout<<(l+2);
		}else{
			cout<<(l+1);
		}
	}else{
		cout<<l;
	}
	return 0;
}

动态规划及线段树题目

沧海的孤塔-chimera

题目描述

个人题目总结:一步两步、沧海的孤塔-chimera(动态规划、线段树以及二分)_第1张图片
输入输出:

输入:
5 3 2
1 2 7 8 9
输出:
19

题目思路及代码

思路: 首先是个动态规划问题,因为是选数的问题,然后又诸多条件,在家上数的数据范围是可以接受n的2次方的。但是n^3就不行了,所以要用线段树进行优化一下

#include
using namespace std;
typedef long long int ll;
const ll maxn=1e5+10;
ll n,m,k;
ll a[maxn],tq[maxn];
struct node{
	ll l,r;
	ll val;
}tr[maxn*4];
ll dp[2010][2010];
void pushup(ll st){
	tr[st].val=max(tr[st*2].val,tr[st*2+1].val);
}
void build(ll st,ll l,ll r){
    tr[st].l=l;
    tr[st].r=r;
    if(l==r){
        tr[st].val=tq[l];
        return ;
    }
    ll mid=(l+r)>>1;
    build(st*2,l,mid);
    build(st*2+1,mid+1,r);
    pushup(st);
    return ;
}
ll getsum(ll st,ll l,ll r,ll pl,ll pr){
	if(l>r)return 0ll;
	if(pl<=l&&r<=pr){
		return tr[st].val;
	}
	ll ans=0;
	ll mid=(l+r)>>1;
	if(pl<=mid){
		ans=max(ans,getsum(st*2,l,mid,pl,pr));
	}
	if(pr>mid){
		ans=max(ans,getsum(st*2+1,mid+1,r,pl,pr));
	}
	return ans;
}
int main(){
	cin>>n>>m>>k;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	build(1,1,n);
	for(int j=1;j<=m;j++){
		for(int i=1;i<=n;i++){
			tq[i]=0;
		}
		for(int i=j;i<=min(k*j,n);i++){
			dp[i][j]=getsum(1,1,n,max(1ll,i-k),max(1,i-1))+a[i];
			tq[i]=dp[i][j];
		}
		build(1,1,n);
	}
	ll ans=0;
	for(int i=n-k+1;i<=n;i++){
		ans=max(ans,dp[i][m]);
	}
	cout<<ans;
	return 0;
}

你可能感兴趣的:(竞赛,动态规划,算法,数据结构,蓝桥杯)