这道题我感觉是一道模板题,以后肯定会碰到类似解法的题目。
题目要找每圈的一个固定值,而且还要特判第一圈刚加上来的值。从这两方面考虑的话,寻找第一圈的最大值,但并不限于第一行。
根据题意,如果满足,那么在前两行一定会出现最大值。让 m 减去最大值之后,表示除去第一次走的,剩下的圈数每回的起点就是最大值之后的点,终点在下一行的最大值点。(如果最大值等于走一圈的的值,那么就等同于多减了一圈,所有的圈数的起点相同,第一行可能前半部分 < 0 舍去)
这里还需要特判,我只说一种情况的理解:在第二行增量为 0 时,表示永远不可能走到 m,意思可以理解为对于第一行起,每在走一行,加的量就是一次走的值(从 max 值之后走也一样,因为每一圈走的量相同,总会走满一整圈(这里还可以变一下题目,改为计算最少的走的步子,而不是圈数,方法相同)),所以 x1 == x2 的时候,表示无增量,踢出即可
上面说的是第一种思路
这里再说一下 s = (a+d-1)/d 表示对 a/d 的向上取整,等同于 ceil((double)a/d)
#include<stdio.h>
#include<math.h>
const long long INF = (1LL<<60);
long long a[100010];
int main()
{
int t;
scanf("%d",&t);
for(int i = 1;i <= t;i++)
{
long long n,m;
scanf("%lld %lld",&n,&m);
long long max = -INF,tmp = 0,x = 0;
int sign = 0;
for(int j = 1;j <= n;j++)
{
scanf("%lld",&a[j]);
x += a[j];
}
for(int k = 1;k <= 2;k++)
{
for(int j = 1;j <= n;j++)
{
// if(k == 1){ //问题所在,为什么不能这么写,因为一旦 break 掉,下面的数据就没办法读取
// scanf("%lld",&a[j]);
// x += a[j];
// }
tmp += a[j];
max = tmp > max ? tmp:max;
if(tmp < 0) tmp = 0;
if(tmp >= m){
sign = k;break;
}
}
if(sign) break;
}
if(sign){
printf("%d\n",sign);continue;
}
if(x <= 0){
printf("-1\n");continue;
}
printf("%lld\n",(m-max+x-1)/x + 2);
}
return 0;
}
这是第二种思路:前后两种情况都考虑,前面先减去两行的值,表示减去第一圈中前面为 0 的值,然后在减去最后一圈的 max 值,中间剩下的就是 n 个整行
max 的值不同,x1,x2的含义不同(和上面方法相比)
#include<stdio.h> //学习前缀和
#include<stdlib.h>
#include<math.h>
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
int a[100005];
const long long INF=(1LL<<60);
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int n;
long long m;
scanf("%d %lld",&n,&m);
long long x1 = 0,x2 = 0;
long long max1 = -INF;
int sign = 0;
long long tmp = 0;
for(int i = 1;i <= n;i++)
{
scanf("%d",&a[i]);
tmp += a[i];
max1 = max(max1,tmp);
// max = max < tmp ? tmp:max;
}
for(int i = 1;i <= n;i++)
{
x1 += a[i];
if(x1 < 0) x1 = 0;
if(x1 >= m)
{
sign = 1;
break;
}
}
if(sign)
{
printf("1\n");continue;
}
x2 = x1;
for(int i = 1;i <= n;i++)
{
x2 += a[i];
if(x2 < 0) x2 = 0;
if(x2 >= m)
{
sign = 2;
break;
}
}
if(sign){
printf("2\n");continue;
}
if(x1 == x2){ //当走完q-n,1-q 判断前缀和是否为 0,即是不是走一圈数不增加
printf("-1\n");continue;
}
long long d = x2-x1;
// 前后两种情况都考虑,前面先减去两行的值,表示减去第一圈中前面为 0 的值,
// 然后在减去最后一圈的 max 值,中间剩下的就是 n 个整行
printf("%lld\n",(long long)ceil((double)(m-max1-x2)/d)+3);
}
return 0;
}