其他分享
首页 > 其他分享> > bzoj4658 rescue

bzoj4658 rescue

作者:互联网

显然的,对于没有贡献的页是没有意义的,所以自然地想到一个朴素的dp

\(dp[i]\)表示看第 i 个关键点死的最少脑细胞

\(dp[i]=min(dp[j]+\lceil\frac{T_i-T_j}{D}\rceil*A)-B_i\)

这个是dp是\(O(n^2)\) 的,如果两个T同时+D,相对关系是不变的,所以与模有关

\(\lceil\frac{T_i-T_j}{D}\rceil = T_i/D - T_j/D+[T_imod D>T_jmod D]\)

\[f[i]=max(max_{0\leq j<x且T_jmodD<T_imodD}(f[j]+\frac{T_j}{D}*A-A),max_{0\leq j<x且T_xmod D\geq T_i mod D}(f_j+\frac{T_j}{D}*A))-\frac{T_i}{D}*A-B_i \]

并且\(E_i-E_j\)不会大于 D ,所以\(\lceil\frac{E_i-E_j}{D}\rceil\)最多只有1,即当\(E_i>E_j\)时产生 1 的贡献

用两个树状数组每次在\(T_imodD\)的位置上加上\(f[i]+\frac{T_i}{D}*A\),并维护前缀和后缀(取模意义下)最大值

传说这是一道JOI的题目,但是没有找到原题,找到的大佬麻烦告诉我一下qwq

点击查看代码
//CAN'T FORGET
//CAN'T FORGET
//CAN'T FORGET

//#pragma GCC optimize("Ofast")
#include<bits/stdc++.h>
using namespace std;
#define _ 0
const long long maxn=1e6+5;
const long long inf=0x3f3f3f3f;
inline long long read()
{
	long long x=0,f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9')
	{
		if(ch=='-')
			f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
	{
		x=(x<<1)+(x<<3)+(ch^48);
		ch=getchar();
	}
	return x*f;
}
long long t[maxn],B[maxn],dp[maxn];
long long b[maxn],nm;
long long d1[maxn],d2[maxn];
long long lowbit(long long x)
{
	return x&(-x);
}
void update1(long long x,long long num)
{
	while(x<=nm)
	{
		d1[x]=max(d1[x],num);
		x+=lowbit(x);
	}
}
long long query1(long long x)
{
	long long res=-inf;
	while(x>0)
	{
		res=max(res,d1[x]);
		x-=lowbit(x);
	}
	return res;
}
void update2(long long x,long long num)
{
	while(x<=nm)
	{
		d2[x]=max(d2[x],num);
		x+=lowbit(x);
	}
}
long long query2(long long x)
{
	long long res=-inf;
	while(x>0)
	{
		res=max(res,d2[x]);
		x-=lowbit(x);
	}
	return res;
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
	freopen("rescue.in","r",stdin);
	freopen("rescue.out","w",stdout);
	memset(d1,-inf,sizeof(d1));
    memset(d2,-inf,sizeof(d2));
    long long k,m,D,A,n;
    cin>>k>>m>>D>>A>>n;
	t[0]=k;
    for(long long i=1;i<=n;i++)
    	cin>>t[i]>>B[i];
    n++;
    t[n]=m;
    for(long long i=0;i<=n;i++)
    	b[++nm]=t[i]%D;
    sort(b,b+nm);
    nm=unique(b,b+nm)-b;
	for(long long i=0;i<=n;i++)
	{
		long long x=t[i]/D,r=t[i]%D;
		r=lower_bound(b,b+nm,r)-b+1;
		if(i!=0)
		{
			dp[i]=query1(r-1)-A*(x+1);
			dp[i]=max(dp[i],query2(nm-r+1)-A*x);
			dp[i]+=B[i];
		}
		long long w=dp[i]+A*x;
		update1(r,w);
		update2(nm-r+1,w);
	}
	cout<<dp[n]<<endl;
	return ~~(0^_^0);
}
/*
Notes:
1.看所有题目
2.注意数据范围
3.想想自己还能做什么而不是做了什么
4.看清题目!!!
5.记得把调试代码删掉!!!!
6.longlong时 1要写成1ll
7.Think twice code once, think once code forever!
*/

标签:ch,frac,rescue,res,bzoj4658,long,max,dp
来源: https://www.cnblogs.com/zxi8-may/p/16309182.html