CF1809F Traveling in Berland - 倍增 -
题目链接:https://codeforces.com/contest/1809/problem/F
题解:
对一个点,考虑怎样在 的时间复杂度内求出答案,联想到倍增
但是,倍增合并的时候只能在两个状态相同的情况下合并,但是如果我们直接从 到 这样算的话,每次剩余的油量是不同的,很难合并。
考虑如果将每次剩余油量都设为 0 的话,就比较容易合并了。
如果当前位置 ,那么直接付清 的钱,然后移动到下一个
如果当前位置 ,且往后第一个不是 ,那么付清 的钱,然后移动到下一个
否则,比如说有 个连续的 ,考虑二分出第一个 的 ,显然在 处先加满油最优,那么到了 处可能刚好够用,也可能需要再买一些。如果需要再买一些的话,显然就是 的额外价格。
这样一来,我们就求得了 代表 往后移动 次的距离,已经此时的价格,倍增即可
对于每个 ,查询的时候就倍增往后跳,注意可能出现没跳完的情况,即某一次 即使是 也 < 剩余的距离(这是有可能的,因为我们每次 都是取的最大值),容易发现此时当前位置一定为 ,直接求出二者的距离,在 处买即可
细节很多,调吐了
// by SkyRainWind
#include <bits/stdc++.h>
#define mpr make_pair
#define debug() cerr<<"Yoshino\n"
#define pii pair<int,int>
#define pb push_back
using namespace std;
typedef long long ll;
typedef long long LL;
const int inf = 1e9, INF = 0x3f3f3f3f, maxn = 4e5+5;
int n,k;
int a[maxn], b[maxn];
ll dist[maxn][20], cost[maxn][20], sum[maxn];
int md(int x){
if(x <= n)return x;
return x-n;
}
void solve(){
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)scanf("%d",&a[i]), a[i+n] = a[i];
for(int i=1;i<=n;i++)scanf("%d",&b[i]), b[i+n] = b[i];
sum[0] = 0;
for(int i=1;i<=2*n;i++)sum[i] = sum[i-1] + a[md(i)];
int cnt = 0;
for(int i=2*n;i>=1;i--){
if(b[i] == 2){
cost[i][0] = 2*a[i];
dist[i][0] = 1;
}else if(cnt == 0){
cost[i][0] = a[i];
dist[i][0] = 1;
}else{
int to = lower_bound(sum+i, sum+i+cnt+1, sum[i-1] + k) - sum;
if(to == i+cnt+1){
cost[i][0] = sum[i+cnt] - sum[i-1];
dist[i][0] = cnt+1;
}else{
int delt = to - i;
if(sum[to] == sum[i-1] + k){
cost[i][0] = k;
dist[i][0] = delt+1;
}else{
cost[i][0] = k + 2 * (sum[to] - sum[i-1] - k);
dist[i][0] = delt+1;
}
}
}
if(b[i] == 2)++ cnt;
else cnt = 0;
}
for(int j=1;j<=18;j++)
for(int i=1;i<=n;i++){
dist[i][j] = dist[i][j-1] + dist[md(i + dist[i][j-1])][j-1];
cost[i][j] = cost[i][j-1] + cost[md(i + dist[i][j-1])][j-1];
}
for(int i=1;i<=n;i++){
ll r = 0, now = i;
int tot = 0;
for(int j=18;j>=0;j--){
if(tot+dist[now][j] <= n)
r += cost[now][j],
tot += dist[now][j],
now = md(now + dist[now][j]);
}
if(tot < n){
r += sum[i+n-1] - sum[i+tot-1];
}
printf("%lld ",r);
}
puts("");
}
signed main(){
int te;scanf("%d",&te);
while(te --)solve();
return 0;
}
分类:
题解
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 记一次.NET内存居高不下排查解决与启示