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

Posted issue是fw

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了1380 D - Berserk And Fireball(思维,贪心)相关的知识,希望对你有一定的参考价值。

LINK

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

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

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

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

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

这里需要分两种情况

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

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

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

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

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

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

z = ( r − l + 1 ) % k z=(r-l+1)\\%k z=(rl+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;
}

以上是关于1380 D - Berserk And Fireball(思维,贪心)的主要内容,如果未能解决你的问题,请参考以下文章

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

Educational Codeforces Round 91 (Rated for Div. 2) D. Berserk And Fireball

如何以 Fire-And-Forget 的形式调用委托调用

codeforces#1148E. Earth Wind and Fire(贪心)

POJ 2003 Hire and Fire (多重链表 树结构 好题)

C# Fire and Forget 任务和丢弃