其他分享
首页 > 其他分享> > 1380 D - Berserk And Fireball(思维,贪心)

1380 D - Berserk And Fireball(思维,贪心)

作者:互联网

LINK

考虑怎样删除区间 [ l , r ] [l,r] [l,r]内的战士

考虑一种无脑的做法,让区间 [ l , r ] [l,r] [l,r]一直使用狂暴,剩下一个和 a l − 1 a_l-1 al​−1或 a r + 1 a_{r+1} ar+1​狂暴就能全部消除

但如果区间中的最大数比 a l − 1 a_{l-1} al−1​和 a r + 1 a_{r+1} ar+1​都大,那么最后它是无法消除的,我们称这种数字为特殊数字

所以应该先用火球术把这种比两边大的数字消掉才行

此时如果 ( r − l + 1 ) < k (r-l+1)<k (r−l+1)<k,不足以使用一次火球则无解,其余都可以消除

这里需要分两种情况

①.当 y ∗ k < = x y*k<=x y∗k<=x时,狂暴比较划算

所以在消除特殊数字的同时还要最小化火球术的次数

当区间中没有特殊数字时,一直狂暴即可,代价 ( r − l + 1 ) ∗ y (r-l+1)*y (r−l+1)∗y

否则,一直在最大数字周围使用狂暴知道只剩 k k k个元素,用一次火球即可消除干净

②.当 y ∗ k > x y*k>x y∗k>x时,火球比较划算

所以在消除特殊数字的同时还要最大化火球术的次数

令 z = ( r − l + 1 ) % k z=(r-l+1)\%k z=(r−l+1)%k,显然可以先用狂暴消掉任意 z z z个数字,然后一直用火球术即可消干净

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn = 1e6+10;
int n,m,t,x,y,k,flag = 1;
int a[maxn],b[maxn],mx[maxn][22],lg[maxn];
unordered_map<int,int>ma;
int get(int l,int r)
{
	int k = lg[r-l+1];
	return max( mx[l][k],mx[r-(1<<k)+1][k] );
}
int solve(int l,int r)
{
	if( l>r )	return 0ll;
	int w = get(l,r);
	if( w>max( a[l-1],a[r+1] ) &&  (r-l+1)<k )	flag = 0;
	if( y*k<=x )
	{
		if( w<max( a[l-1],a[r+1] ) )	return y*(r-l+1);
		else if( w>max( a[l-1],a[r+1]) )	return ( r-l+1-k )*y+x;			
	}
	else
	{
		int z = (r-l+1)%k;
		return (r-l+1)/k*x+z*y;	
	} 
}
signed main()
{
	ios::sync_with_stdio( false ); cin.tie( 0 ); cout.tie( 0 );
	for(int i=2;i<=1000000;i++)	lg[i] = lg[i>>1]+1;
	ma.clear();
	cin >> n >> m >> x >> k >> y;
	for(int i=1;i<=n;i++)	cin >> a[i], ma[a[i]] = i, mx[i][0] = a[i];
	for(int j=1;j<=20;j++)
	for(int i=1;i+(1<<j)-1<=n;i++)
		mx[i][j] = max( mx[i][j-1],mx[i+(1<<(j-1))][j-1] );
	int las = 0, ans = 0;
	for(int i=1;i<=m;i++)
	{
		cin >> b[i];
		int x = ma[b[i]];
		if( !ma.count( b[i] ) )	flag = 0;
		else
		{
			if( x<las )	flag = 0;
			else	las = x;
		}
	}
	b[0] = 0;
	for(int i=1;i<=m;i++)
	{
		if( i==1 )
		{
			if( a[1]==b[1] )	continue;
			ans += solve( 1,ma[b[1]]-1 );
		}
		else
			ans += solve( ma[b[i-1]]+1,ma[b[i]]-1 );
	}
	if( a[n]!=b[m] )	ans += solve( ma[b[m]]+1,n );
	if( flag==0 )	ans = -1;
	cout << ans << endl;
}

标签:火球,ma,数字,int,狂暴,maxn,Fireball,1380,Berserk
来源: https://blog.csdn.net/jziwjxjd/article/details/120595416