代码:
题意,第一个数为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 <bitsstdc++.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