Codeforces 1397C

1397C - Multiples of Length


题意

给定一个数列({a})

每次你需要选中一个区间([L,R])

然后对区间内每个数字进行一次操作,让(a_i)变成(a_i+k),并且满足(k mod (R-L+1)=0)

你只能严格做三遍操作,使得最终所有数字变成(0)


限制

Time limit per test: 1 second

Memory limit per test: 256 megabytes

输入限制

(1leq nleq 10^5)

(-10^9leq a_ileq 10^9)

输出限制

(1leq l,rleq n)

(-10^{18}leq b_ileq 10^{18}, b_i mod (r-l+1)=0)




思路一(复杂版)

这个版本的思路主要是为了应对输出更为严格的限制下的题目

但本题的输出要求为(±10^{18})以内(跟没限制一样)

所以这里可能会讲得过于麻烦

只想看本题能过的简单版可以下拉到思路二

该部分输出的值可以证明一定在(±[(10^5-1)+(10^5-1) imes(10^5-1)+10^9]≈±1.1 imes10^{10})以内

进一步对正负进行讨论后可以优化到(±10^{10})以内(但我没进一步讨论qwq)

引入 1

假设(m)是奇数,那么(m-1)是偶数

对于某个数(xin [0,m-1)),可以得到((x+m) mod (m-1)=(x+1) mod (m-1))

观察到在该式子中,加上(m)的意义与加上(1)的意义相同

所以可以得到([x+(m-1-x)*m] mod (m-1)=0)

也就是对于(x),加上(m-1-x)倍的(m)后得到的值取模(m-1)等于(0)

引入 2

假设(m)是偶数,那么(m-1)是奇数

对于某个数(xin [1,m)),可以得到([x+(m-1)] mod m=(x-1) mod m)

观察到在该式子中,加上(m-1)的意义与减去(1)的意义相同

所以可以得到([x+x*(m-1)] mod m=0)

也就是对于(x),加上(x)倍的(m-1)后得到的值取模(m)等于(0)

得到的结论

一个数,加上一个奇数的倍数,最终肯定能表示成一个偶数的倍数

本题

根据上述结论,可以根据总长度(n)的奇偶性进行分类讨论


如果总长度(n)为奇数

我们可以直接拿区间([1,n])进行处理

将所有数字加上(n)(奇数)的倍数,并表示成(n-1)(偶数)的倍数

首先将数字转移到([0,n))

tmp=(a[i]%n+n)%n;

再计算要加上多少倍,并加上这些倍数

tmp+=((n-1)-tmp)*n;

此时的(tmp)就表示成了(n-1)的倍数,且((tmp-a[i]) mod n=0)

这一步就将(a[i])变成(tmp),输出差值(tmp-a[i])即可

因为上面一步将所有数字全部变成了(n-1)的倍数

那么这一步只需要选择([1,n-1])这个区间,将所有数字全部变成(0)并输出差值即可

最后选择([n,n])单个数字变成(0)并输出差值即可


如果总长度(n)为偶数

我们可以先拿区间([1,n-1])进行处理

将所有数字加上(n-1)(奇数)的倍数,并表示成(n)(偶数)的倍数

首先将数字转移到([0,n-1))

tmp=(a[i]%(n-1)+(n-1))%(n-1);

然后直接加上倍数即可

tmp+=tmp*(n-1);

这里的操作同上,只需要输出差值(tmp-a[i])即可,并将(a[i]=tmp)

然后选择区间([n,n]),将这个数字直接变成(0)并输出差值即可

最后选择区间([1,n]),将所有数字变成(0)后输出差值即可





代码一

(93ms/1000ms)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

ll a[100050];

int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%lld",&a[i]);
    
    if(n==1)
    {
        puts("1 1");
        printf("%lld
",-a[1]);
        puts("1 1");
        puts("0");
        puts("1 1");
        puts("0");
        return 0;
    }
    
    if(n&1) //长度为奇数,选一遍消除两遍
    {
        printf("%d %d
",1,n);
        for(int i=1;i<=n;i++)
        {
            if(a[i]%(n-1)==0) //已经是n-1的倍数的话则无需进行操作
                printf("0 ");
            else
            {
                ll tmp=(a[i]%n+n)%n;
                tmp+=((n-1)-tmp)*n;
                printf("%lld ",tmp-a[i]); //先输出差值
                a[i]=tmp; //再替换
            }
        }
        putchar('
');
        
        printf("%d %d
",1,n-1);
        for(int i=1;i<n;i++)
            printf("%lld ",-a[i]); //输出相反数即可,下同
        putchar('
');
        
        printf("%d %d
",n,n);
        printf("%lld
",-a[n]);
    }
    else //长度为偶数,选两遍消除一遍
    {
        printf("1 %d
",n-1);
        for(int i=1;i<n;i++)
        {
            if(a[i]%n==0)
                printf("0 ");
            else
            {
                ll tmp=(a[i]%(n-1)+(n-1))%(n-1);
                tmp+=tmp*(n-1);
                printf("%lld ",tmp-a[i]);
                a[i]=tmp;
            }
        }
        putchar('
');
        
        printf("%d %d
",n,n);
        printf("%lld
",-a[n]);
        a[n]=0;
        
        printf("%d %d
",1,n);
        for(int i=1;i<=n;i++)
            printf("%lld ",-a[i]);
        putchar('
');
    }
    
    return 0;
}



思路二(简单版)

明显的,对于某个数字(x)

(n imes x)肯定是(n)的倍数

(n imes x-x=(n-1) imes x),差值也肯定是(n-1)的倍数

那么只需要选择一段长度为(n-1)的区间,将所有数字乘以(n)

再将单独的那个数字变成(0)

最后将所有数字变成(0)即可

对于这种方法,输出的最大值约为(10^9 imes 10^5=10^{14}),在输出允许的范围内




代码二

(109ms/1000ms)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

ll a[100050];

int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%lld",&a[i]);
    
    if(n==1)
    {
        puts("1 1");
        printf("%lld
",-a[1]);
        puts("1 1");
        puts("0");
        puts("1 1");
        puts("0");
        return 0;
    }
    
    printf("%d %d
",1,n-1);
    for(int i=1;i<n;i++)
    {
        printf("%lld ",a[i]*(n-1));
        a[i]*=n;
    }
    putchar('
');
    
    printf("%d %d
",n,n);
    printf("%lld
",-a[n]);
    a[n]=0;
    
    printf("%d %d
",1,n);
    for(int i=1;i<=n;i++)
        printf("%lld ",-a[i]);
    putchar('
');
    
    return 0;
}

原文地址:https://www.cnblogs.com/stelayuri/p/13587485.html