{ }codelper
累加while 循环64 位整数P0296

越升越远的下一级

游戏角色从等级 1、经验值 0 开始。
升到下一级所需的经验值叫做门槛。
最初的门槛是 a,最初的增幅是 d。
q 个事件依次发生,每个事件给出一个不为 0 的整数 x。
x 为正时获得经验值。
如果这个事件是没有中断的连续正数事件中的第 k 个,就给经验值加上 x + (k − 1) × b。
它是第一个事件或者上一个事件是罚分时 k = 1;上一个事件是正数时,k 比那个事件的 k 大 1。
x 为负时是罚分。
从经验值中减去 −x,结果小于 0 时把经验值设为 0。
罚分会打断连续,所以下一个正数事件重新算第 1 次。
每个事件改完经验值之后,只要等级小于 M 且经验值不小于门槛,就重复下面的步骤:经验值减去门槛,等级加 1,门槛加上增幅,然后增幅加上 g。
所以一个事件可以连升几级,剩下的经验值留到下一次。
等级不会下降。
等级到 M 之后不再上升,经验值不再扣减,只会继续累积。
第一行给出 a、d、g、M、b,用一个空格隔开;第二行给出 q;接下来 q 行每行给出一个 x。
对每个事件,在一行中输出处理完该事件后的等级和经验值,用一个空格隔开。
最后一行输出单个事件中升级数的最大值(一次也没升过则为 0)。

输入
1 ≤ a ≤ 1,000,000,000,0 ≤ d ≤ 1,000,000,0 ≤ g ≤ 1,000,1 ≤ M ≤ 10,000,0 ≤ b ≤ 1,000,000,1 ≤ q ≤ 1,000,1 ≤ |x| ≤ 1,000,000,000。
全部是整数,只给出数字,不带逗号
输出
q + 1 行。
每个事件的等级和经验值,最后一行是单个事件中升得最多的级数。
数字不带逗号
样例 1 · stdin
10 5 2 5 3
6
12
60
-25
50
7
100
stdout
2 2
4 28
4 3
5 22
5 32
5 138
2
main.py
输入(stdin)

运行时这些行会依次作为 input()/标准输入传入(运行中不会等待输入)。

$ 就绪

请在电脑上打开以编写和运行代码。在手机上可以查看题目和题解。

其他语言怎么写?查看各语言题解 · 8 种语言题解

循环每转一圈都接着上一圈的值继续累加的变量有五个(经验值、门槛、增幅、连续次数、最多升级数)。
xp += x 这样的 += 八种语言都有,只有 Python 没有 level++(写 level += 1)。
陷阱 ① 一个事件可能连升几级,所以要用 while(Craykon 当)而不是 if,在“经验值不小于门槛期间”重复。
用 if 的话,示例的第二个事件会停在等级 3。
② 门槛加上增幅之后,增幅也要加上 g。
一个累加量叠在另一个累加量上,很容易漏掉一行。
③ 把 >= 写成 >,经验值正好等于门槛时就升不了级。
④ 到最高等级时要用 level < M 停下,否则会升过 M。
⑤ 罚分不能让经验值低于 0:Python max(0, v),JS・TS・Java Math.max(0, v),C# Math.Max(0, v),C++ std::max(0LL, v)(两个参数类型必须相同,所以是 0LL 而不是 0),Craykon 数学.较大值(0, v)。
C 标准库没有整数用的 max 函数,所以写 if (xp < 0) xp = 0;。
⑥ 出现罚分时要把连续次数清零,连续第 k 次的奖励是 (k − 1) × b 而不是 k × b。
⑦ 经验值会涨到约 1.5 万亿,门槛也可能超过 21 亿,int(约 21 亿)装不下。
C・C++ 用 long long(printf 用 %lld),Java・C# 用 long。
Python 的整数没有大小限制,JS・TS・Craykon 的数在 2^53(约 9 × 10^15)以内整数是精确的,所以可以直接用。

Pythonmain.py · 31 行
import sys lines = sys.stdin.read().split("\n")a, d, g, M, b = map(int, lines[0].split())q = int(lines[1]) level, xp = 1, 0need, step = a, d  # 문턱과 증가폭: 오를 때마다 둘 다 쌓인다streak = 0  # 연달아 얻은 횟수best = 0  # 한 사건에서 가장 많이 오른 레벨 수out = []for i in range(q):    x = int(lines[2 + i])    if x > 0:        streak += 1        xp += x + (streak - 1) * b    else:        streak = 0        xp = max(0, xp + x)    ups = 0    # 한 번에 여러 레벨을 오를 수 있으니 if가 아니라 while    while level < M and xp >= need:        xp -= need        level += 1        need += step        step += g        ups += 1    best = max(best, ups)    out.append(f"{level} {xp}")out.append(str(best))print("\n".join(out))
JavaScriptmain.js · 32 行
const lines = require("fs").readFileSync(0, "utf8").split("\n");const [a, d, g, M, b] = lines[0].trim().split(/\s+/).map(Number);const q = Number(lines[1]); let level = 1, xp = 0;let need = a, step = d; // 문턱과 증가폭: 오를 때마다 둘 다 쌓인다let streak = 0; // 연달아 얻은 횟수let best = 0; // 한 사건에서 가장 많이 오른 레벨 수const out = [];for (let i = 0; i < q; i++) {  const x = Number(lines[2 + i]);  if (x > 0) {    streak += 1;    xp += x + (streak - 1) * b;  } else {    streak = 0;    xp = Math.max(0, xp + x);  }  let ups = 0;  // 한 번에 여러 레벨을 오를 수 있으니 if가 아니라 while  while (level < M && xp >= need) {    xp -= need;    level += 1;    need += step;    step += g;    ups += 1;  }  best = Math.max(best, ups);  out.push(`${level} ${xp}`);}out.push(String(best));console.log(out.join("\n"));
TypeScriptmain.ts · 34 行
import { readFileSync } from "node:fs"; const lines: string[] = readFileSync(0, "utf8").split("\n");const [a, d, g, M, b]: number[] = lines[0].trim().split(/\s+/).map(Number);const q = Number(lines[1]); let level = 1, xp = 0;let need = a, step = d; // 문턱과 증가폭: 오를 때마다 둘 다 쌓인다let streak = 0; // 연달아 얻은 횟수let best = 0; // 한 사건에서 가장 많이 오른 레벨 수const out: string[] = [];for (let i = 0; i < q; i++) {  const x = Number(lines[2 + i]);  if (x > 0) {    streak += 1;    xp += x + (streak - 1) * b;  } else {    streak = 0;    xp = Math.max(0, xp + x);  }  let ups = 0;  // 한 번에 여러 레벨을 오를 수 있으니 if가 아니라 while  while (level < M && xp >= need) {    xp -= need;    level += 1;    need += step;    step += g;    ups += 1;  }  best = Math.max(best, ups);  out.push(`${level} ${xp}`);}out.push(String(best));console.log(out.join("\n"));
JavaMain.java · 41 行
import java.util.Scanner; public class Main {    public static void main(String[] args) {        Scanner sc = new Scanner(System.in);        long a = sc.nextLong(), d = sc.nextLong(), g = sc.nextLong();        int M = sc.nextInt();        long b = sc.nextLong();        int q = sc.nextInt();         int level = 1;        long xp = 0; // 1조 넘게 쌓여서 int로는 모자란다        long need = a, step = d; // 문턱과 증가폭: 오를 때마다 둘 다 쌓인다        long streak = 0; // 연달아 얻은 횟수        int best = 0; // 한 사건에서 가장 많이 오른 레벨 수        StringBuilder out = new StringBuilder();        for (int i = 0; i < q; i++) {            long x = sc.nextLong();            if (x > 0) {                streak += 1;                xp += x + (streak - 1) * b;            } else {                streak = 0;                xp = Math.max(0, xp + x);            }            int ups = 0;            // 한 번에 여러 레벨을 오를 수 있으니 if가 아니라 while            while (level < M && xp >= need) {                xp -= need;                level += 1;                need += step;                step += g;                ups += 1;            }            best = Math.max(best, ups);            out.append(level).append(' ').append(xp).append('\n');        }        out.append(best).append('\n');        System.out.print(out);    }}
C#Main.cs · 49 行
using System;using System.Text; class Program{    static void Main()    {        string[] p = Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries);        long a = long.Parse(p[0]), d = long.Parse(p[1]), g = long.Parse(p[2]);        int M = int.Parse(p[3]);        long b = long.Parse(p[4]);        int q = int.Parse(Console.ReadLine().Trim());         int level = 1;        long xp = 0; // 1조 넘게 쌓여서 int로는 모자란다        long need = a, step = d; // 문턱과 증가폭: 오를 때마다 둘 다 쌓인다        long streak = 0; // 연달아 얻은 횟수        int best = 0; // 한 사건에서 가장 많이 오른 레벨 수        var output = new StringBuilder();        for (int i = 0; i < q; i++)        {            long x = long.Parse(Console.ReadLine().Trim());            if (x > 0)            {                streak += 1;                xp += x + (streak - 1) * b;            }            else            {                streak = 0;                xp = Math.Max(0, xp + x);            }            int ups = 0;            // 한 번에 여러 레벨을 오를 수 있으니 if가 아니라 while            while (level < M && xp >= need)            {                xp -= need;                level += 1;                need += step;                step += g;                ups += 1;            }            best = Math.Max(best, ups);            output.Append(level).Append(' ').Append(xp).Append('\n');        }        output.Append(best).Append('\n');        Console.Write(output);    }}
C++main.cpp · 38 行
#include <algorithm>#include <iostream> int main() {    std::ios::sync_with_stdio(false);    long long a, d, g, b;    int M, q;    std::cin >> a >> d >> g >> M >> b >> q;     int level = 1;    long long xp = 0;             // 1조 넘게 쌓여서 int로는 모자란다    long long need = a, step = d; // 문턱과 증가폭: 오를 때마다 둘 다 쌓인다    long long streak = 0;         // 연달아 얻은 횟수    int best = 0;                 // 한 사건에서 가장 많이 오른 레벨 수    for (int i = 0; i < q; i++) {        long long x;        std::cin >> x;        if (x > 0) {            streak += 1;            xp += x + (streak - 1) * b;        } else {            streak = 0;            xp = std::max(0LL, xp + x); // 두 인수의 타입이 같아야 해서 0LL        }        int ups = 0;        // 한 번에 여러 레벨을 오를 수 있으니 if가 아니라 while        while (level < M && xp >= need) {            xp -= need;            level += 1;            need += step;            step += g;            ups += 1;        }        best = std::max(best, ups);        std::cout << level << ' ' << xp << '\n';    }    std::cout << best << '\n';}
Cmain.c · 38 行
#include <stdio.h> int main(void) {    long long a, d, g, b;    int M, q;    scanf("%lld %lld %lld %d %lld %d", &a, &d, &g, &M, &b, &q);     int level = 1;    long long xp = 0;             /* 1조 넘게 쌓여서 int로는 모자란다 */    long long need = a, step = d; /* 문턱과 증가폭: 오를 때마다 둘 다 쌓인다 */    long long streak = 0;         /* 연달아 얻은 횟수 */    int best = 0;                 /* 한 사건에서 가장 많이 오른 레벨 수 */    for (int i = 0; i < q; i++) {        long long x;        scanf("%lld", &x);        if (x > 0) {            streak += 1;            xp += x + (streak - 1) * b;        } else {            streak = 0;            xp += x;            if (xp < 0) xp = 0;        }        int ups = 0;        /* 한 번에 여러 레벨을 오를 수 있으니 if가 아니라 while */        while (level < M && xp >= need) {            xp -= need;            level += 1;            need += step;            step += g;            ups += 1;        }        if (ups > best) best = ups;        printf("%d %lld\n", level, xp);    }    printf("%d\n", best);    return 0;}
Craykonmain.cray · 41 行
p = 控制台.读数字();a = p[0];d = p[1];g = p[2];M = p[3];b = p[4];q = 控制台.读行().转数字(); level = 1;xp = 0;need = a; // 문턱step = d; // 증가폭: 오를 때마다 문턱과 함께 쌓인다streak = 0; // 연달아 얻은 횟수best = 0; // 한 사건에서 가장 많이 오른 레벨 수循环 (i = 0; i < q; i++){    x = 控制台.读行().转数字();    如果 (x > 0)    {        streak += 1;        xp += x + (streak - 1) * b;    }    否则    {        streak = 0;        xp = 数学.较大值(0, xp + x);    }    ups = 0;    // 한 번에 여러 레벨을 오를 수 있으니 만약이 아니라 동안    当 (level < M && xp >= need)    {        xp -= need;        level += 1;        need += step;        step += g;        ups += 1;    }    best = 数学.较大值(best, ups);    控制台.输出(level + " " + xp);}控制台.输出(best);