P1081 [NOIP2012 进步组] 开车观光

[复制链接]
发表于 2024-7-30 08:13:20 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
思绪:

首先令 \(nxt1_i\) 表示右侧最近的城市间隔(\(id1_i\) 为编号),令 \(nxt2_i\) 表示右侧第二近的城市编号(\(id2_i\) 为编号);可以利用 set 找出离这个城市最近的 \(4\) 个城市(前面两个,后面两个)。
定义:

  • \(f_{i,j}\) 表示从 \(i\) 点出发走 \(2^j\) 轮末了到达的位置。
  • \(dp1_{i,j}\) 表示从 \(i\) 点出发走 \(2^j\) 轮末了 A 走过的间隔。
  • \(dp2_{i,j}\) 表示从 \(i\) 点出发走 \(2^j\) 轮末了 B 走过的间隔。
初始化:

\[f_{i,0} = id1_{id2_i}\]

\[dp1_{i,0} = nxt2_{i}\]

\[dp2_{i,0} = nxt1_{id2_i}\]
状态转移方程为:

\[f_{i,j} = f_{f_{i,j-1},j-1}\]

\[dp1_{i,j} = dp1_{i,j-1} + dp1_{f_{i,j-1},j-1}\]

\[dp2_{i,j} = dp2_{i,j-1} + dp2_{f_{i,j-1},j-1}\]
此时对于询问 \(1\) 和询问 \(2\):

  • 本质上是求出从每个城市出发后 \(A\) 走的间隔与 \(B\) 走的间隔。
  • 那么考虑从高位到低位贪心,即设当前跳到了 \(s\) 点,若 \(dp1_{s,i} + dp2_{s,i} \le x\),可以从 \(s\) 跳到 \(f_{s,i}\),需要令 \(x \gets x - (dp1_{s,i} + dp2_{s,i})\),然后继续遍历 \(i-1\) 位。
  • 因为是 A 先开车,所以 A 可能会在末了一轮竣事后还能再开上一次,需要特判。
时间复杂度为 \(O((N+Q) \log N)\)。
完整代码

[code]#include#define Add(x,y) (x+y>=mod)?(x+y-mod)x+y)#define lowbit(x) x&(-x)#define pi pair#define pii pair#define iip pair#define ppii pair#define fi first#define se second#define full(l,r,x) for(auto it=l;it!=r;it++) (*it)=x#define Full(a) memset(a,0,sizeof(a))#define open(s1,s2) freopen(s1,"r",stdin),freopen(s2,"w",stdout);using namespace std;typedef double db;typedef unsigned long long ull;typedef long long ll;bool Begin;const ll N=1e5+10,M=18,INF=1e18;inline ll read(){    ll x=0,f=1;    char c=getchar();    while(c'9'){        if(c=='-')          f=-1;        c=getchar();    }    while(c>='0'&&c
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表