迷之序列

Problem Description

MLE 得到了 QAQ 的真传,但 QAQ 为了检验 MLE 智商是否可以真正领悟,于是出了这一道题:给出 n 个数的序列,先把每个数逆序(如 120 变为 21,123 变为 321),将会产生 n 个新数,我们把它称作序列 A。

之后对序列 A 中的 n-1 个数进行 q 次操作,每次操作将会把序列 A 上的某个数替换成另一个数,并询问序列 A 中任取连续的一段数,如何取才能使这段数的和最大,请你输出最大值。

Input

输入数据有多组(数据组数不超过 100)。

对于每组数据:

  • 第一行输入 n, q (1 <= n <= 10000, 1 <= q <= 100) 分别表示数字个数和操作次数
  • 接下来的一行输入 n 个正整数,最大不超过 10000
  • 接下来的 q 行,每行输入 2 个整数,分别为要替换的数的位置 xi (1 <= xi <= n) 和要修改的值 yi (-10000 <= yi <= 10000)

当 n = 0 时输入结束。

Output

对于每组数据第一行输出 "Case #x:" (不包括引号,冒号后无空格),x 表示当前为第几组数据。之后对应 q 次操作每次操作输出一行,表示查询的答案。

Example Input
5 2
1 2 3 4 5
2 -5
2 5
3 3
45 12 32
3 -5
1 5
2 10
0
Example Output
Case #1:
12
18
Case #2:
75
26
15

代码如下:

动态规划

#include<stdio.h>
int f(int x)
{
    int i , b[6],top = 0;
    while(x!=0)
    {
        b[top] = x%10;
        top++;
        x /=10;
    }
    x = 0;
    for(i = 0;i<top;i++)
        x = x*10+b[i];
    return x;
}
int main()
{
    int n ,i ,q,a[100010],b[100010],max,x,y,cas =1;
    while(scanf("%d",&n)!=EOF&&n!=0)
    {
        scanf("%d",&q);
        for(i = 0;i<n;i++)
          {
            scanf("%d",&a[i]);
            a[i] = f(a[i]);
          }
          printf("Case #%d:\n",cas);
          while(q--)
          {
              scanf("%d %d",&x,&y);
              a[x-1] = y;
              b[0] = a[0];
              max = b[0];
              for(i = 1;i<n;i++)
              {
                  if(b[i-1]>0)
                  {
                      b[i] = b[i-1]+a[i];
                  }
                  else
                  {
                      b[i] = a[i];
                  }
                  if(b[i]>max)
                    max = b[i];
              }
              printf("%d\n",max);
          }
          cas++;


    }
    return 0;
}


分治递归
第一种情况:a[1...n]的最大子段和和a[1...n/2]最大子段和相同
第二种情况:a[1...n]的最大子段和和a[n/2+1...n]最大子段和相同
第三种情况:a[1...n]的最大子段和是a[i....j]任意一段和 1<=i<= n/2 , n/2+1 <=j<= n 较复杂

#include<stdio.h>
#define max 100010
int a[max];
int maxsub(int left,int right)
{
    int mid, i;
    int sum,left_sum,right_sum;
    int left_max,right_max;
    mid = (left+right)/2;
    if(left==right)
    {
        return a[left]>0?a[left]:0;
    }
    else
    {
        left_sum = maxsub(left,mid);
        right_sum = maxsub(mid+1,right);
        sum = 0;
        left_max = 0;
        for(i = mid;i>=left;i--)
        {
            sum+=a[i];
            if(sum>left_max)
            {
                left_max = sum;
            }
        }
        sum = 0;
        right_max = 0;
        for(i = mid+1;i<=right;i++)
        {
            sum+=a[i];
            if(sum>right_max)

            {
                right_max = sum;
            }
        }
        sum = right_max+left_max;
        if(sum<left_sum)
            sum = left_sum;
        if(sum<right_sum)
            sum = right_sum;
    }
    return sum;
}
int f(int x)
{
    int i ,b[6],top;
    while(x!=0)
    {
        b[top] = x%10;
        top++;
        x/=10;
    }
    x = 0;
    for(i = 0;i<top;i++)
    {
        x = x*10+b[i];
    }
    return x;
}
int main()
{
    int n ,i , q ,x ,y ,cas = 1;
    while(scanf("%d",&n)!=EOF&&n!=0)
    {
        scanf("%d",&q);
        for(i =0 ;i<n;i++)
        {
            scanf("%d",&a[i]);
            a[i] = f(a[i]);
        }
        printf("Case #%d:\n",cas);
        while(q--)
        {
            scanf("%d %d",&x,&y);
            a[x-1] = y;
            printf("%d\n",maxsub(0,n-1));
        }
        cas++;
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值