Codeforces Round #709 (Div. 2, based on Technocup 2021 Final Round)-B. Restore M

46 阅读4分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

@TOC

Технокубок 2021 - Финал-B. Restore Modulo

传送门 Time Limit: 1 second Memory Limit: 256 megabytes

Problem Description

For the first place at the competition, Alex won many arrays of integers and was assured that these arrays are very expensive. After the award ceremony Alex decided to sell them. There is a rule in arrays pawnshop: you can sell array only if it can be compressed to a generator.

This generator takes four non-negative numbers nn, mm, cc, ss. nn and mm must be positive, ss non-negative and for cc it must be true that 0c<m0 \leq c < m. The array aa of length nn is created according to the following rules:

  • a1=s mod ma_1=s\ mod\ m, here xmody denotes remainder of the division of xx by yy;
  • ai=(ai1+c) mod ma_i=(a_{i−1}+c)\ mod\ m for all ii such that 1<in1<i≤n.

For example, if n=5n = 5, m=7m = 7, c=4c = 4, and s=10s = 10, then a=[3,0,4,1,5]a = [3, 0, 4, 1, 5].

Price of such an array is the value of mm in this generator.

Alex has a question: how much money he can get for each of the arrays. Please, help him to understand for every array whether there exist four numbers nn, mm, cc, ss that generate this array. If yes, then maximize mm.

Input

The first line contains a single integer tt (1t1051 \leq t \leq 10^5) — the number of arrays.

The first line of array description contains a single integer nn (1n1051 \leq n \leq 10^5) — the size of this array.

The second line of array description contains nn integers a1,a2,,ana_1, a_2, \ldots, a_n (0ai1090 \leq a_i \leq 10^9 ) — elements of the array.

It is guaranteed that the sum of array sizes does not exceed 10510^5.

Output

For every array print:

Sample Input

6
6
1 9 17 6 14 3
3
4 2 2
3
7 3 4
3
2 2 4
5
0 1000000000 0 1000000000 0
2
1 1

Sample Onput

19 8
-1
-1
-1
2000000000 1000000000
0

题目大意

给你一个包含nn个数字的数组aa,让你找是否存在nmcsn、m、c、s,使得:

  • a1=s mod ma_1=s\ mod\ m
  • ai=(ai1+c) mod ma_i=(a_{i−1}+c)\ mod\ m

如果存在,要找最大的mm


解题思路

首先根据题目要求,需要满足以下条件:

  • m>0m>0
  • n>0n>0
  • s0s\geq0
  • 0c<m0\leq c<m

然后根据aia_iai1a_{i-1}的关系,有ai=(ai1+c) mod ma_i=(a_{i−1}+c)\ mod\ m,又有c<mc<m。那么只有两种情况:

  • ai=ai1+ca_i=a_{i−1}+c
  • ai+m=ai1+ca_i+m=a_{i−1}+c

即:

  • aiai1=ca_i-a_{i−1}=c
  • aiai1=cma_i-a_{i−1}=c-m

因此,我们需要关注aia_iai1a_{i-1}的差值diffdiff。 不难发现,这样的差值最多有两个,再多就无法解出答案。

多说无益,上例子:

样例1:1 9 17 6 14 3

计算aia_iai1a_{i-1}的差值。分别为8 8 -11 8 -119-117-96-1714-63-14) 只有两种:8-11 因此我们得到方程组:{c=8cm=8\left\{\begin{array}{lcl}c=8\\或\\c-m=8\\\end{array} \right.{c=11cm=11\left\{\begin{array}{lcl}c=-11\\或\\c-m=-11\\\end{array} \right. 两个方程组需要同时满足。 解方程组: 若第一个方程组中c=8c=8成立,则第二个方程组中cm=11c-m=-11必须成立,得 {c=8m=19\left\{\begin{array}{lcl}c=8\\m=19\\\end{array} \right. 若第一个方程组中cm=8c-m=8成立,则第二个方程组中c=11c=-11必须成立,得 {c=11m=19\left\{\begin{array}{lcl}c=-11\\m=-19\\\end{array} \right. 第一个解满足题目要求,第二个解不满足要求,所以最大的mm1919,此时c=8c=8,样例1输出19 8

样例2:4 2 2

计算aia_iai1a_{i-1}的差值。分别为-2 02-42-2) 只有两种:-20 因此我们得到方程组:{c=2cm=2\left\{\begin{array}{lcl}c=-2\\或\\c-m=-2\\\end{array} \right.{c=0cm=0\left\{\begin{array}{lcl}c=0\\或\\c-m=0\\\end{array} \right. 两个方程组需要同时满足。 解方程组得: {c=2m=0\left\{\begin{array}{lcl}c=-2\\m=0\\\end{array} \right.{c=0m=0\left\{\begin{array}{lcl}c=0\\m=0\\\end{array} \right. 都不满足条件,输出-1

样例3:7 3 4

计算得两种差值:-41 解得c=-1 m=-5c=1 m=5 显然第一组不符合题意,但是第二组可要小心啦 aa中的元素都是mod mmod\ m得到的,怎么可能比mm还大呢? 所以又产生一个条件:

  • m>max{ai}m>max\{a_i\}

样例4:2 2 4

计算得两种差值:02 解得c=0 m=-2c=2 m=2 第一组m<0m<0,第二组m<4m<4 不符合

样例5:0 1000000000 0 1000000000 0

计算得两种差值:1000000000-1000000000 解得c=1000000000 m=2000000000c=-1000000000 m=-2000000000 第一组m=2000000000 c=1000000000符合题意 第二组不符合题意

样例6:1 1

计算只得一种差值:0 只有一个方程组: {c=0cm=0\left\{\begin{array}{lcl}c=0\\或\\c-m=0\\\end{array} \right.cm=0c-m=0成立时,mm可以无穷大。 顾输出特殊数字0


AC代码

#include <bits/stdc++.h>
using namespace std;
#define mem(a) memset(a, 0, sizeof(a))
#define dbg(x) cout << #x << " = " << x << endl
#define fi(i, l, r) for (int i = l; i < r; i++)
#define cd(a) scanf("%d", &a)
typedef long long ll;
int a[100010];
int main()
{
    int N;
    cin >> N;
    while (N--)//N组测试数据
    {
        int n;
        cd(n);//scanf("%d",&n);
        int M = 0;
        for (int i = 0; i < n; i++)
        {
            scanf("%d", &a[i]);
            M = max(M, a[i]);//顺便记录最大值,因为m必须大于MAX{a}
        }
        int LeiJiChuXianDeDiff = 0; //控制在0,1,2
        int ChuXianDeDiff[2];//出现的diff
        bool canNot = 0; //canNot为1时代表不可以
        for (int i = 1; i < n; i++)//计算差值
        {
            int thisDiff = a[i] - a[i - 1];//差值diff
            if (!LeiJiChuXianDeDiff) //还没有出现过diff
            {
                LeiJiChuXianDeDiff++;//累计出现的diff
                ChuXianDeDiff[0] = thisDiff;//记录下这个diff
            }
            else if (LeiJiChuXianDeDiff == 1) //出现过一个diff了
            {
                if (thisDiff != ChuXianDeDiff[0]) //这次的和上次的不一样
                {
                    LeiJiChuXianDeDiff++;//累计出现的diff
                    ChuXianDeDiff[1] = thisDiff;//记录下这个diff
                }
            }
            else //出现过2个diff了
            {
                if (thisDiff != ChuXianDeDiff[0] && thisDiff != ChuXianDeDiff[1]) //和出现过的两个diff都不一样
                {
                    canNot = 1;//3个方程组不能同时满足
                    puts("-1");
                    break;
                }
            }
        }
        if (!canNot) //还存在可能
        {
            if (LeiJiChuXianDeDiff <= 1)//没有出现过diff或只出现过一个diff
            {
                puts("0");//只有一个方程组,m可以无穷大,输出0
            }
            else//出现了2个diff
            {
                int KeYiDeM = 0;//可以的m
                int ans = 0;//答案m
                int diff = ChuXianDeDiff[0];//第一个
                int m = diff - ChuXianDeDiff[1];
                int ansDiff = 0;//答案c
                if (m > M && diff >= 0) //可以了一种情况
                {
                    KeYiDeM++;
                    ans = m;
                    ansDiff = diff;
                }
                diff = ChuXianDeDiff[1];//更新diff
                m = diff - ChuXianDeDiff[0];//更新m
                if (m > M && diff >= 0) //可以了一种情况
                {
                    KeYiDeM++;
                    if (KeYiDeM == 1) //就这一种情况
                    {
                        ans = m;
                        ansDiff = diff;
                    }
                    else //有两种情况,需要取最大
                    {
                        if (ans > m) //第一种情况的m更大
                        {
                            //不用动
                        }
                        else //第二种情况m更大
                        {
                            ans = m;
                            ansDiff = diff;
                        }
                    }
                }
                if (KeYiDeM) //不是0
                {
                    printf("%d %d\n", ans, ansDiff);
                }
                else
                {
                    puts("-1");
                }
            }
        }
    }
    return 0;
}

总结

若存在,需满足:

  • 出现的不同的diffdiff的个数2\leq2
  • mm大于所有的aa的最大值
  • m>0m>0
  • n>0n>0
  • s0s\geq0
  • 0c<m0\leq c<m

同步发文于我的CSDN,原创不易,转载请附上原文链接哦~
Tisfy:blog.csdn.net/Tisfy/artic…