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