51nod 1402 最大值 3级算法题 排序后修改限制点 时间复杂度O(m^2)

代码:

 

 

题意,第一个数为0,相邻的数相差0或者1,有一些点有限制,不大于给定值,求这组数中可能的最大的那个数。

 

这题我们看一个例子:第5个数的限制为2

1 2 3 4 5 6 7 8 9 

0 1 2 3 2

第一个数一定是0,那么我们可以看出其中最大的数为3。

 

第二个例子:第6个数的限制为2

1 2 3 4 5 6 7 8 9

0 1 2 3 3 2

其中最大的数为3。

 

关于奇数和偶数,我们可以总结出一个规律

假设左边的数的下标为left,右边的数的下标为right,左边的数为value1,右边的数为value2。

我们可以得出其中的最大值mx = (right-left-(value2-value1))/2+value2。

如果还是不清楚,可以画一画图,这是化简得来的。

 

 

有了这个公式我们就好办了,每个限制点分类讨论,1.能达到限制值,2.不能达到限制值。

 

 

 

最后要注意的一点是:这题有个坑

可能后面的限制点会约束前面的限制点。

例如:

第3个点限制为2,第4个点限制为0

如果只管前面的点,不顾后面的点的话,

1 2 3 4 5

0 1 2 0

这样会产生矛盾,导致第3个点与第4个点差值大于1。

 

 

所以我们需要先把限制条件处理好,

我们把所有限制点,对其他点的约束,处理好之后,再按照最前面的公式,和分类讨论来做就可以AC了。

 

 

 

我处理限制点的方法是:考虑到只有限制值小的点会对限制值大的产生影响,

            我对这些数排个序,把每个点对,比它大的点的约束修改好之后,再来算就好了。

 

可能会考虑到的问题是:一个点A对后面的某个点B约束修改之后,可能不再是顺序的。

            这不是问题,因为B是被A修改来的,它不会对左边的数产生影响。

           反证法:如果能产生影响的话,说明A没有修改完所有可以改变的点,产生矛盾,所以不会对前面的点产生影响。

 

 

代码:

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

//用来排序的数组 
struct node{
    int index;
    int value;
    int con;   //存在原数组s1中的位置 
}s[55];


int s1[55][2];  // 原数组,输入数据 

bool cmp(node x,node y){
    if(x.value == y.value) return x.index < y.index;
    else return x.value < y.value;
}

int main() {
  int t,n,m;
  cin >> t;
  while(t--){
      cin >> n >> m;
      for(int i = 0;i < m; i++){
          cin >> s1[i][0] >> s1[i][1];
          s[i].index = s1[i][0];
          s[i].value = s1[i][1];
          s[i].con = i;
        }
      sort(s,s+m,cmp);
      for(int i = 0;i < m; i++){
          for(int j = i+1;j < m; j++){
              if(s[i].value < s[j].value){
                  if(abs(s[j].index-s[i].index)+s[i].value < s[j].value){
                      s[j].value = abs(s[j].index-s[i].index)+s[i].value;
                      s1[s[j].con][1] = abs(s[j].index-s[i].index)+s[i].value;
                    }
                }
            }
        }
      
      int k1,k2;
      int value = 0;int index = 1;
        int ans  = 0;
        s1[m][0] = n,s1[m][1] = 100000000;
        for(int i = 0;i <= m; i++){
          k1 = s1[i][0];k2 = s1[i][1];
          int mx = k1-index+value;
          if(mx <= k2){
              value = mx;
              index = k1;
              ans = max(ans,mx);
            }else{
                int l = k1-index+1-(k2-value)-2;
                ans = max(ans,(l+1)/2+k2);
                value = k2;
                index = k1;
            }
        }
        cout << ans << endl;
    }
  return 0;
}
//  writen by zhangjiuding 

 

转载于:https://www.cnblogs.com/zhangjiuding/p/7637812.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值