NOIP2023游记
justalearner · · 个人记录
坐标广东,暂估分 214,估计(肯定)进不了队,不知道能拿几等。
upd:分数200(暴力打挂),压线一等!
第一题很简单,由于字典序是全序,所以用先算出串最小和最大的可能的字典序(我们一般称之为:排序),然后用计排算出排名来,然后随便判断就可以了。
第二题一眼并查集,对每个变量建两个点,分别代表
第三题、第四题只打了暴力。。。(听说T3是原,T4是简单的线段树优化DP???)
第二题一开始没有特判
赛前在看算导和黑书(疯狂安利黑书!)。不过学的全都没考,考了也全都不会就是了
总结:如果没有秒切,也要多给思考的时间
T4题解
T4是DP!!!
使用离散化,于是
Part 0
各种指数算法。
Part 1
DP。令
这样我们就得到了
或者离散化的版本
时间复杂度
Part 2
用单调队列优化掉那个
Part 3
在Part 1的基础上,用线段树实时维护
观察到决策分为三部分:
然后就没有然后了,区间
时间复杂度
T4
//调了半天才发现多测没清线段树。
#include<cstdio>
#include<algorithm>
#include<cstring>
const int N=2e5+10;
typedef long long ll;
ll f[N];
struct interval{int l,r,v;}a[N];
bool operator<(const interval &a,const interval &b){return a.r<b.r;}
struct node{ll max,plus;}t[N*4];int m2;
int d;int fm[N];
void pushup(int p){t[p].max=std::max(t[p<<1].max,t[p<<1|1].max);}
void pushdown(int p)
{
if(t[p].plus)
{
t[p<<1].plus+=t[p].plus;
t[p<<1].max+=t[p].plus;
t[p<<1|1].plus+=t[p].plus;
t[p<<1|1].max+=t[p].plus;
t[p].plus=0;
}
}
int time[N];
void build(int l=1,int r=m2,int o=1)
{
t[o].plus=0;
if(l==r)
{
t[o].max=1ll*time[l]*d;
return;
}
int mid=l+r>>1;
build(l,mid,o<<1);
build(mid+1,r,o<<1|1);
pushup(o);
}
void add(const int &L,const int &R,const ll &v,int l=1,int r=m2,int o=1)
{
if(L<=l&&r<=R){t[o].max+=v;t[o].plus+=v;return;}
int mid=l+r>>1;
pushdown(o);
if(L<=mid) add(L,R,v,l,mid,o<<1);
if(mid<R) add(L,R,v,mid+1,r,o<<1|1);
pushup(o);
}
ll max(const int &L,const int &R,int l=1,int r=m2,int o=1)
{
if(L<=l&&r<=R) return t[o].max;
int mid=l+r>>1;ll ret=0;
pushdown(o);
if(L<=mid) ret=max(L,R,l,mid,o<<1);
if(mid<R) ret=std::max(ret,max(L,R,mid+1,r,o<<1|1));
return ret;
}
int main()
{
freopen("run.in","r",stdin);
freopen("run.out","w",stdout);
int c,T;scanf("%d%d",&c,&T);
while(T--)
{
int n,m,k;scanf("%d%d%d%d",&n,&m,&k,&d);
for(int i=1,y;i<=m;i++)
{
scanf("%d%d%d",&a[i].r,&y,&a[i].v),a[i].l=a[i].r-y+1;
time[i*2-1]=a[i].l;time[i*2]=a[i].r;
}
std::sort(time+1,time+m*2+1);
m2=0;
for(int i=1;i<=m*2;i++)
{
if(i==1||time[i]!=time[i-1])
time[++m2]=time[i];
}
std::sort(a+1,a+m+1);
memset(f,0,sizeof f);
memset(fm,0,sizeof fm);
int j=1;build();
for(int i=1;i<=m2;i++)
{
for(;j<=m&&a[j].r<=time[i];j++) add(1,std::upper_bound(time+1,time+m2+1,a[j].l)-1-time,a[j].v);
f[i]=std::max(f[i-1],-1ll*(time[i]+1)*d+max(std::lower_bound(time+1,time+m2+1,time[i]-k+1)-time,i));
if(i==std::upper_bound(time+1,time+m2+1,time[i+1]-2)-1-time&&f[i]>fm[i+1]) add(i+1,i+1,f[i]-fm[i+1]),fm[i+1]=f[i];
if(i==std::upper_bound(time+1,time+m2+1,time[i+2]-2)-1-time&&f[i]>fm[i+2]) add(i+2,i+2,f[i]-fm[i+2]),fm[i+2]=f[i];
}
printf("%lld\n",f[m2]);
}
}