反向操作

第一次写博客诶,好高兴!!!

反向操作
题目大意:
在一个首尾相接的正整数数列中,做一次操作的意思是说将每个数变成这

个数和相邻两个数的和,现在给出操作后的数列,请求出初始时的序列。
输入:
第一行一个数N表示序列的长度
下面N行每行一个数表示这个操作后的序列

输出:
输出N行每行一个数,表示操作前的序列

样例输入:
3
5
5
5

样例输出:
2
1
2
(当然也有其他的解,请读者自己判断。。。)
数据范围
N<=10000,输入中的所有数都满足<=109

看到这个题,突然发现好像可以写暴力啊!!!!!
然后看看数据范围。。。。。。

其实这个题是一个数列题(对OIER来说应该没有问题)
应分三种情况考虑,一个是N%3 == 0时,一个是N%3 == 1时,一个是N%3 == 2时


反正只要求出一组解,我们就可以用特殊的XX技巧

(a[i]为ans[i-1]+ans[i]+ans[i+1]的和,ans为要输出的答案)

首先,在N%3 == 1时,我们可以把1~N的编号分为{{1},{2~4},{5~7},……

{N-2~N}},然后可以把分好的这个序列分为1和其他数,因为N%3 == 1,所以就可

以理所当然可以算出其他数ans[2]到ans[n]的和,然后我们可以设sum为sum=(a

[1]+a[2]……+a[n])/3,这就是p=ans[1]+ans[2]……+ans[n]的值,然后我

们将p-sum就求出了a[1]的值。然后我们用类似的方法可以求出a[2],得到a[1]和

a[2]的值,就可以求出数列的值。

在N%3 == 2的时候与N%3 == 1的时候类似。

最复杂的莫过于N%3 == 0的时候了。这样也可以先假设ans[1]=0,然后可以一次

求出ans[4],ans[7]……ans[3i+1]的所有值。假如求出的值出现了负数,找出

最小值Min,把每个数加上Min+1,以此保证每个数都大于0。然后也可以用类似的

方法可以设ans[2]=0求出ans[5],ans[8]……ans[3i+2],然后和3i+1的情况一

样,去处理。最后得出a[3i+1]与a[3i+2]自然可以得出a[3i]。

好吧,这个题这样就做完了。

下面放上代码

#include <cstdio>
#include <algorithm>
#define MAXN 10005
using namespace std;
long long ans[MAXN] = {0}, a[MAXN] = {0};
long long sum = 0;
int main()
{
    int n;
    scanf("%d", &n);
    for (int i = 1; i <= n; ++i)
    {
        scanf("%I64d", &a[i]);
        sum = sum + a[i];
    }
    sum = sum / 3;
    if (n == 1)
        ans[1] = 1;
    else
    if (n == 2)
        ans[1] = 1, ans[2] = a[1] - 1;
    else
    if (n == 3)
        ans[1] = 1, ans[2] = 1, ans[3] = a[1] - 2;
    else
    if (n % 3 == 1)
    {
        long long ss = 0;
        for(int i = 2;i <= n; i = i + 3)
            ss = ss + a[i];
        ans[n] = sum - ss;
        ss=0;
        for (int i = 3;i <= n; i = i + 3)
            ss = ss + a[i];
        ans[1] = sum - ss;
        ans[2] = a[1] - ans[n] - ans[1];
        for (int i = 3; i < n; ++i)
            ans[i] = a[i - 1] - ans[i - 1] - ans[i - 2];
    }
    else
    if (n % 3 == 2)
    {
        long long ss = 0;
        for(int i = 2;i <= n; i = i + 3)
            ss = ss + a[i];
        ans[1] = ss - sum;
        ss = 0;
        for (int i = 1; i < n; i = i + 3)
            ss = ss + a[i];
        ans[n] = ss - sum;
        ans[2] = a[1] - ans[n] - ans[1];
        for (int i = 3; i < n; ++i)
            ans[i] = a[i - 1] - ans[i - 1] - ans[i - 2];
    }
    else
    {
        long long Min = 0;
        for (int i = 4; i <= n; i = i + 3)
        {
            ans[i] = ans[i - 3] + a[i - 1] - a[i - 2];
            Min = min(Min, ans[i]);
        }
        for (int i = 1; i <= n; i = i + 3)
            ans[i] = ans[i] - Min + 1;
        Min = 0;
        for (int i = 5; i <= n; i = i + 3)
        {
            ans[i] = ans[i - 3] + a[i - 1] - a[i - 2];
            Min = min(Min, ans[i]);
        }
        for (int i = 2; i <= n; i = i + 3)
            ans[i] = ans[i] - Min + 1;
        for (int i = 3; i <= n; i = i + 3)
            ans[i] = a[i - 1] - ans[i - 1] - ans[i - 2];
    }
    for (int i = 1; i <= n; ++i)
        printf("%I64d\n" ,ans[i]);
    return 0;
}

谢谢大家!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值