游戏

18 篇文章 0 订阅
10 篇文章 0 订阅

游戏
都快CSP复赛了,我发现我贪心还是不好。。。。
上来先来个dp,发现写了个假结论。。。
——————————————————————————————————————
其实这题应该考虑贪心,我们
枚 举 3 个 数 为 例 子 , i , j , k , 发 现 直 接 去 k 的 价 值 和 间 接 去 k 的 价 值 分 别 为 枚举3个数为例子,i,j,k,发现直接去k的价值和间接去k的价值分别为 3ijkkk
( k − i ) ∗ a [ k ] (k-i)*a[k] (ki)a[k]
( j − i ) ∗ a [ j ] + ( k − j ) ∗ a [ k ] (j-i)*a[j]+(k-j)*a[k] (ji)a[j]+(kj)a[k]
发 现 当 a [ k ] > a [ j ] 的 时 候 , 肯 定 直 接 去 k 更 优 发现当a[k]>a[j]的时候,肯定直接去k更优 a[k]>a[j]k
接下来只用找出后面的最大值就行了
本 人 做 法 O ( n l o g 2 n ) 本人做法O(nlog^2n) O(nlog2n)

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

typedef long long ll;
const int N=100010;
int n,a[N],lg[N];
int st[N][18];
int maxn(int l,int r){
	if(r<l) return 0;
	int len=(r-l+1);
	int ll=lg[len];
	return max(st[l][ll],st[r-(1<<ll)+1][ll]);
}
int find(int l,int r){
	while(l<r){
	int mid=(l+r)>>1;
	if(maxn(l,mid)>maxn(mid+1,r)){
		 r=mid;
	 }
	 else l=mid+1;
    }
	return l;
}
int summ=0,lastt=1;
int main(){
    scanf("%d",&n);
    lg[0]=1;
    for(int i=2;i<=n;i++){
    	if(lastt*2==i){
    		lastt=i;
    		lg[i]=++summ;
    	    continue;
		}
    	lg[i]=summ;
    }
    for(int i=1;i<=n;i++){
    	scanf("%d",&a[i]);
    	st[i][0]=a[i];
    }
    int up=lg[n];
    for(int i=1;i<=up;i++){
    	for(int l=1;l+(1<<i)-1<=n;l++){
    		int r=(l+(1<<i)-1);
    		st[l][i]=max(st[l][i-1],st[l+(1<<(i-1))][i-1]);
    	}
    }
    ll ans=0;
    int l=0;a[0]=0;
    while(l<n){
    	int nxt=find(l+1,n);
    	ans+=1ll*(nxt-l)*a[nxt];
    	l=nxt;
    }
    printf("%lld",ans);
}

其它O(n)做法
1.建递增队列,使队列中元素单调递增

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

const int N=100010;
int n,a[N];
int sstack[N][2];
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
    	scanf("%d",&a[i]);
    }
    int cnt=0;
    for(int i=1;i<=n;i++){
    	sstack[++cnt][0]=a[i],sstack[cnt][1]=i;
    	while(sstack[cnt-1][0]<sstack[cnt][0]&&cnt>1){
    		sstack[cnt-1][0]=sstack[cnt][0];
    		sstack[cnt-1][1]=sstack[cnt][1];
    		cnt--;
    	}
    }
    long long ans=0;
    for(int i=1;i<=cnt;i++){
    	ans+=1ll*(sstack[i][1]-sstack[i-1][1])*sstack[i][0];
    }
    printf("%lld",ans);
}

2.逆序处理最大值,因为本题是求后面的最大值,所以直接求即可

P.S 遇到貌似dp的题一定要先想贪心

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值