Loading

AtCoder-abc258_e Packing Potatoes

Packing Potatoes

二分 + 循环

无限多的物品,模拟是不现实的,考虑从 \(n\) 种物品下手

在第 \(i\) 种物品中,我们可以计算,装满盒子之后需要连续放多少个物品,而且还能知道装完之后是在哪种物品停下来

因此我们考虑建立一条有向边,\(i -> j\) 代表如果当前盒子第一个放入的是第 \(i\) 种物品,则下一个盒子的第一个放入的物品是第 \(j\) 种物品

这样每种物品都会发出一条有向边,总共是 \(n\) 条有向边

不难发现,从第一个物品开始往后跳转,如果这样一直跳转下去的话,会存在一个循环

我们只要对询问的答案,判断一下是否能进入循环,如果不进入,就直接返回答案;如果进入,就取模判断一下最后在循环的哪一步停下来

这样一个无穷大的问题就变成一个循环取模的问题

建立有向边的时候考虑用 前缀和 + 二分 的方式来求,剩下的都是亿点细节问题

细节:

  • 二分的时候,可能会存在 \(n\) 种物品全部取出来都不够装一个盒子的,因此要提前将 \(x\)\(sum\) 取模

  • 求取答案未进入到循环之前,不能进入有向边一个一个找,要提前预处理好进入循环前,第 \(i\) 个盒子是哪一步,不然会 TLE

  • 如果是从 \(1\) 开始的,注意好下标,特别是取模的时候

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <string>
#include <queue>
#include <functional>
#include <map>
#include <set>
#include <cmath>
#include <cstring>
#include <deque>
#include <stack>
using namespace std;
typedef long long ll;
#define pii pair<int, int>
const ll maxn = 2e5 + 10;
const ll inf = 1e16 + 10;
ll num[maxn], sum[maxn], nex_num[maxn];
int nex[maxn], vis[maxn];
int alp[maxn];

int main()
{
    int n, q, x;
    cin >> n >> q >> x;
    for(int i=1; i<=n; i++)
    {
        cin >> num[i];
        sum[i] = sum[i-1] + num[i];
    }
    ll rx = x / sum[n];
    x %= sum[n];
    for(int i=1; i<=n; i++)
    {
        int way = 0;
        nex_num[i] = rx * n;
        if(sum[n] - sum[i-1] >= x)
        {
            way = lower_bound(sum + 1, sum + 1 + n, x + sum[i-1]) - sum;
            nex_num[i] += way - i + 1;
        }
        else
        {
            way = lower_bound(sum + 1, sum + 1 + n, x - sum[n] + sum[i-1]) - sum;
            nex_num[i] += n - i + 1 + way;
        }
        nex[i] = way + 1;
        if(nex[i] > n) nex[i] = 1;
    }
    int now = 1, dep = 1;
    while(vis[now] == 0)
    {
        vis[now] = dep;
        alp[dep] = now;
        dep++;
        now = nex[now];
    }
    ll pre = vis[now] - 1, rnd = dep - vis[now];
    while(q--)
    {
        ll k;
        cin >> k;
        ll ans = 0;
        if(k <= pre)
            ans = nex_num[alp[k]];
        else
        {
            k -= pre + 1;
            k %= rnd;
            ans = nex_num[alp[k + pre + 1]];
        }
        cout << ans << endl;
    }
    return 0;
}
posted @ 2022-07-04 15:31  dgsvygd  阅读(99)  评论(0)    收藏  举报