题目链接:https://codeforces.com/contest/1809/problem/F
题解:
对一个点,考虑怎样在 \(O(\log n)\) 的时间复杂度内求出答案,联想到倍增
但是,倍增合并的时候只能在两个状态相同的情况下合并,但是如果我们直接从 \(i\) 到 \(i+1\) 这样算的话,每次剩余的油量是不同的,很难合并。
考虑如果将每次剩余油量都设为 0 的话,就比较容易合并了。
如果当前位置 \(b_i=2\),那么直接付清 \(2\times a_i\) 的钱,然后移动到下一个
如果当前位置 \(b_i=1\),且往后第一个不是 \(2\),那么付清 \(a_i\) 的钱,然后移动到下一个
否则,比如说有 \(k\) 个连续的 \(2\),考虑二分出第一个 \(sum[l..r] \geq k\) 的 \(r\),显然在 \(b_i\) 处先加满油最优,那么到了 \(r\) 处可能刚好够用,也可能需要再买一些。如果需要再买一些的话,显然就是 \(2\times (sum[l..r]-k)\) 的额外价格。
这样一来,我们就求得了 \(dist[i][0]\) 代表 \(i\) 往后移动 \(2^0\) 次的距离,已经此时的价格,倍增即可
对于每个 \(i\),查询的时候就倍增往后跳,注意可能出现没跳完的情况,即某一次 \(i\) 即使是 \(dist[i][0]\) 也 < 剩余的距离(这是有可能的,因为我们每次 \(dist\) 都是取的最大值),容易发现此时当前位置一定为 \(b_i=1\),直接求出二者的距离,在 \(b_i=1\) 处买即可
细节很多,调吐了
// 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;
}
标签:cnt,dist,Berland,int,sum,CF1809F,cost,maxn,Traveling
From: https://www.cnblogs.com/SkyRainWind/p/17255212.html