首页 > 其他分享 >题解:NOIP2023 天天爱打卡

题解:NOIP2023 天天爱打卡

时间:2024-08-12 17:20:15浏览次数:7  
标签:cnt int 题解 tag max NOIP2023 打卡 mx rk

题解:NOIP2023 天天爱打卡

  • 标签:线段树优化dp
  • 先考虑一个朴素的dp, \(f[i]\) 表示前 \(i\) 天, 第 \(i\) 天必打卡能得到的最大能量,有转移:

\[f[i]=\max_{j=i-k+1}^{i} (val(j,i) - d \times (i-j+1) + \max_{p=1}^{j-2} f[p]) \]

  • \(val(j,i)\) 表示第 \(j\sim i\) 天完成的挑战.

  • 乍一看是 \(O(n^2mk)\).

  • 优化1: $ \max_{p=1}^{j-2} f[p]$ 可以前缀 \(max\) 优化.

  • 优化2:把每个挑战挂在它的终点上,这样每个挑战只会被访问一次.

  • 优化3:记 \(g[j] = val(j,i) - d \times (i-j+1) + \max_{p=1}^{j-2} f[p]\), 那么 \(f[i]=\max_{j=i-k+1}^{i} g[j]\)

    这个东西可以用线段树优化,只需要维护区间加,区间求max.

    #include<bits/stdc++.h>
    #define F(i,l,r) for(int i(l);i<=(r);++i)
    #define G(i,r,l) for(int i(r);i>=(l);--i)
    #define int long long
    #define pii pair<int,int>
    using namespace std;
    using ll = long long;
    const int N=2e5+105;
    int c,T,n,m,d,k,cnt=0;
    int x[N],y[N],v[N],g[N],rk[N];
    int mx[N<<2],tag[N<<2];
    vector<pii> e[N];
    inline void pushup(int u){
    	mx[u]=max(mx[u*2],mx[u*2+1]);
    }
    inline void pushdown(int p,int l,int r){
    	if(tag[p]!=0){
    		mx[p*2]+=tag[p];
    		mx[p*2+1]+=tag[p];
    		tag[p*2]+=tag[p];
    		tag[p*2+1]+=tag[p];
    		tag[p]=0;
    	}
    }
    inline void update(int p,int l,int r,int x,int y,int z){
    	if(x>y) return ;
    	if(x<=l && r<=y){
    		tag[p]+=z;
    		mx[p]+=z;
    		return ;
    	}
    	pushdown(p,l,r);
    	int mid=(l+r)>>1;
    	if(x<=mid) update(p*2,l,mid,x,y,z);
    	if(y>mid) update(p*2+1,mid+1,r,x,y,z);
    	pushup(p);
    }
    inline int ask(int p,int l,int r,int x,int y){
    	if(x<=l && r<=y){
    		return mx[p];
    	} pushdown(p,l,r);
    	int mid=(l+r)>>1,maxn=0;
    	if(x<=mid) maxn=max(maxn,ask(p*2,l,mid,x,y));
    	if(y>mid) maxn=max(maxn,ask(p*2+1,mid+1,r,x,y));
    	return maxn;
    }
    inline int get(int x){
    	return lower_bound(rk+1,rk+cnt+1,x)-rk;
    }
    signed main(){
    //	freopen("run.in","r",stdin);
    //	freopen("run.out","w",stdout);
    	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    	cin>>c>>T;
    	while(T--){
    		memset(mx,0,sizeof(mx));
    		memset(tag,0,sizeof(tag));
    		g[0]=0;
    		cnt=0;
    		cin>>n>>m>>k>>d;
    		F(i,1,m) {
    			cin>>x[i]>>y[i]>>v[i];
    			y[i]=x[i]-y[i]+1;
    			rk[++cnt]=x[i];
    			rk[++cnt]=y[i];
    		}
    		sort(rk+1,rk+cnt+1); cnt=unique(rk+1,rk+cnt+1)-rk-1;
    		F(i,1,cnt) e[i].clear(); 
    		F(i,1,m){
    			int xx=get(x[i]),yy=get(y[i]);
    			e[xx].push_back({yy,v[i]});
    		}
    		F(i,1,cnt){
    			if(rk[i]-rk[i-1]>1 || i==1)	update(1,1,cnt,i,i,g[i-1]-d);		
    			else update(1,1,cnt,i,i,g[i-2]-d);		
    			update(1,1,cnt,1,i-1,(rk[i-1]-rk[i])*d);
    //			update(1,1,cnt,i,i,((i==1||rk[i]-rk[i-1]>1)?g[i-1]:g[i-2])-d);
    //			if(i>1) update(1,1,cnt,1,i-1,-(rk[i]-rk[i-1])*d);
    			int siz=e[i].size();
    			F(j,0,siz-1){
    				pii o=e[i][j];
    				update(1,1,cnt,1,o.first,o.second);	
    			}
    			int lx = lower_bound(rk+1,rk+cnt+1,rk[i]-k+1)-rk; 
    			g[i]=max(g[i-1],max(0ll,ask(1,1,cnt,lx,i)));
    		}
    		cout<<g[cnt]<<"\n";
    	}
    	return 0;
    }
    

    总结

  • 个人觉得本题的难点应该是要把朴素的dp想对,比如我一开始就没有敢往一维dp上想。

  • 再一个就是前两个小优化是不难的,要力求写准确。

  • 最后就是离散化之后修改和查询有一些细节很需要注意!

标签:cnt,int,题解,tag,max,NOIP2023,打卡,mx,rk
From: https://www.cnblogs.com/superl61/p/18355368

相关文章

  • [题解]P2292 [HNOI2004] L 语言
    P2292[HNOI2004]L语言注:下文中,\(s[l\simr]\)表示截取字符串\(s\)的第\(l\)个字符到第\(r\)个字符。文字描述的字符串下标从\(1\)开始,但代码实现从\(0\)开始。我们建出AC自动机后,有一个比较暴力的思路。我么用\(f[i]\)表示待查找字符串\(t\)的长度为\(i\)前缀是否满足......
  • AtCoder ABC 366题解
    前言本文部分思路来自于网络,仅供参考。A-Election2题目大意给定两个市长候选人的票数,求结果是否已经确定。解题思路如果剩下的人全部投票给票少的人票少的人也不能赢,则结果就已经确定了。code#include<bits/stdc++.h>usingnamespacestd;intmain(){intn,t,......
  • ABC366D 题解
    第一眼是想写\(kd-tree\)的。然后发现这就是一道三维前缀和的板子题。三维前缀和要想学习三维前缀和,我们首先得了解前缀和的概念,并且学会一维、二维前缀和。什么是前缀和前缀和是容斥原理的典型应用。这种优化方式可以使求和操作的时间复杂度降低到\(O(1)\)(但是需要提前预......
  • 题解:AT_abc351_f [ABC351F] Double Sum
    关于某c人士强制偷袭代码导致AT号被封,\({\color{red}\mathrm{警钟敲碎}}\)。题意一个长\(n\)的数组\(a\),求所有顺序对中两元素之差的和。分析听说有大佬2min切掉。很明显,暴力过不去。考虑计算每个元素的贡献。设\(id\)为该元素之前所有比它小的元素个数,\(sum\)表示这些......
  • tensorboard_logger库无法导入的问题解决
    一、问题描述最近在学习深度学习时,从大神们那里copy的代码中有用到tensorboard_logger这个库的东西,所以很自然地就用condainstall或者pip去安装它,但是结果是:python开源库里面没有这东西。这就让我很苦恼,所以只能自己动手,丰衣足食了。 二、解决方法首先找到tensorboard_logge......
  • ABC366 G - XOR Neighbors 题解
    发现题目实质上就是让你构造一组\(a_{1,2,\dots,n}\),有一些限制,要求一些\(a\)异或起来是\(0\)。看到\(n\le60\),果断列异或方程组,用异或高斯消元。具体地,有\(n\)个方程组,\(a_{i,j}\)表示第\(i\)个方程中\(j\)的系数。对于每一个变量\(i\),要把\(j>i\)的方程中的第......
  • 【题解】P3356 火星探险问题
    \(\large\mathfrak{1st.\Preamble|}\)前言这都什么年代了网络流24题居然还能写题解!个人认为这篇题解讲的还是比较详细的。\(\large\mathfrak{2nd.\Solution|}\)题解看到题目的第一眼,我的反应是这样的:这不跟深海机器人问题差不多吗?Ctrl-CCtrl-V秒了。不过我还是讲讲怎......
  • ABC366D 题解
    Solution题意简述给你一个正整数\(N\)和\(N^3\)个非负整数,表示为\(A_{x,y,z}\)其中\(1\leqx,y,z\leqN\)。您将得到以下格式的\(Q\)个查询,必须按顺序处理。对于第\(i\)次查询\((1\leqi\leqQ)\),您将得到一个整数元组\((Lx_i,Rx_i,Ly_i,Ry_i,Lz_i,......
  • 逆序对数列(P2513) - 题解
    [HAOI2009]逆序对数列原题链接题目描述对于一个数列\(\{a_i\}\),如果有\(i<j\)且\(a_i>a_j\),那么我们称\(a_i\)与\(a_j\)为一对逆序对数。若对于任意一个由\(1\simn\)自然数组成的数列,可以很容易求出有多少个逆序对数。那么逆序对数为\(k\)的这样自然数数列到底......
  • ABC366F Maximum Composition 题解
    ABC366FMaximumComposition题解题目大意给定\(N\)个一次函数\(f_i(x)=a_ix+b_i\),从中选出\(K\)个函数\(f_{p_1},f_{p_2},\dots,f_{p_K}\),使得\(f_{p_1}(f_{p_2}(\dotsf_{p_K}))\)最大,求最大值。Solve考虑这样一种情况:我已经选定\(p_{k+1},p_{k+1},\dots,p_K\),现......