AtCoder Beginner Contest 258 E题思路整理

题意:对无数个土豆进行打包,土豆的重量分布规律为W0..Wn-1,Wn的一个序列循环,如果此时已装土豆的重量 >=x 则打成一个包,有 q 次询问,每次询问求第 k 次打包装的土豆的数量。

大致思路是模拟+找循环节,

不难想到,打包的过程中存在一个循环节,因为由一个起点可以唯一确定一个终点,而一个序列最多有n个起点,考虑最差的情况,如果前 n 次打包的起点都不相同,则第 n+1 次打包的起点一定会与之前的某个起点重复,这样就出现了循环节。

类似于这样。。

而我们的目标就是记录这个 <=n 的循环节,以及出现循环节之前的答案

由于 n 次循环后必会出现循环节,所以我们模拟 n 次打包的过程

代码具体实现细节:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N = 1e6 + 7;
ll a[N], p[N], ans0[N], ans[N];
//ans0[] 记录前n项的答案
//ans[] 记录循环节的答案 
int main()
{

    ll n, q, x, s = 0;
    cin >> n >> q >> x;
    for (ll i = 0; i < n; i++)
    {
        cin >> a[i];
        a[i + n] = a[i];
        s += a[i];
    }
    for (ll i = 0; i < 2 * n; i++)
    {
        p[i] = i == 0 ? a[i] : p[i - 1] + a[i]; //前缀和,方便之后求和
    }
    ll u = 0, k;//u为起点
    //模拟前n次
    for (ll i = 0; i < n; i++)
    {
        ans0[i] = x / s * n;  //当x大于s时,
        //(p[]是递增的),二分查找终点k,此时的k距离起点u一定<=n,所以只需对p[]扩展2倍
        k = x % s == 0 ? u - 1 : lower_bound(p + u, p + 2 * n, (u == 0 ? x % s : p[u - 1] + x % s)) - p; // p[u]-p[u-1]>=x%s
        ans0[i] += k - u + 1;
        u = (k + 1) % n;//更新起点
    }
    //此时的u必与之前的某个起点相同
    ll tot = 0, wc = u;//当n次之后开始从0记录循环节
    while (1)
    {
        ans[tot] = x / s * n;
        k = x % s == 0 ? u - 1 : lower_bound(p + u, p + 2 * n, (u == 0 ? x % s : p[u - 1] + x % s)) - p;
        ans[tot++] += k - u + 1;
        u = (k + 1) % n;
        if (wc == u)
            break;
    }
    ll v;
    while (q--)
    {
        cin >> v;
        v--;//注意,只有从第0次开始,才能取余操作
        cout << (v < n ? ans0[v] : ans[(v - n) % tot]) << endl;//当v大于n时一定处于循环节中
    }

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值