2 条题解
-
0
题目大意
求出序列中前缀和后缀的最小差值即可
解题思路
可以推数学公式逃课()
先把题目要你求最小值的式子:化简一下。
代入每一项后,得到原式 =
两段等差数列求和,得到原式 $ = ∣\frac{(k+k+x−1)\times x}{2}−\frac{(k+x+k+n−1)\times (n-x)}{2}| $
化简并整理,得到原式 。
令
又因为 ,所以 ,,则。综上可知 在区间 内必定有且只有一个根。
令,利用求根公式解出方程的根。
设这个根为 ,则显然与 最接近的两个函数值是 与 ,取个绝对值找其中的较小值即可。
代码
void solve() { int n,k; cin >> n >> k; int b=(2*k-1); int c=(n*(2*k+n-1)/2); double g=(1.0*b*b)+(4.0*c); double x=(1.0*sqrt(g)-1.0*b)/2.0; int nx=x; int y1=(int)abs(nx*nx+b*nx-n*(2*k+n-1)/2); int y2=(int)abs((nx+1)*(nx+1)+b*(nx+1)-n* (2*k+n-1)/2); cout << min(y1,y2) <<endl; }
时间复杂度
O(T).
(如果用二分做,那时间复杂度要再乘上一个 。)
-
0
二分答案
令 为,为,很明显题解是求min(|sum1-sum2|). 根据i的增大,sum1-sum2很明显具有单调性,二分的位置,再让当前位置减一则是的位置,分别求出两个位置的答案,求最小值即可。
#include<bits/stdc++.h> using namespace std; #define int long long int a[200005]; int jc[200005]; const int mod =1e9+7; int l1,r1; bool check(int x)//判断 { int sum1=(x-l1+1)*(l1+x)/2;//等差数列求和 int sum2=(r1-x)*(r1+x+1)/2; if(sum1>=sum2) { return 1; } else return 0; } signed main() { int t; cin >> t; while(t--) { int o,p; cin >> o >> p; l1=p,r1=p+o-1; int l=l1,r=r1; while(l<=r)//二分 { int mid=(l+r)/2; if(check(mid)) { r=mid-1; } else l=mid+1; } r=r+1; int sum1=(r-l1+1)*(l1+r)/2; int sum2=(r1-r)*(r1+r+1)/2; int ans=0; ans=abs(sum1-sum2); r--; sum1=(r-l1+1)*(l1+r)/2; sum2=(r1-r)*(r1+r+1)/2; ans=min(ans,abs(sum1-sum2)); cout <<ans<<'\n'; } }
- 1
信息
- ID
- 1048
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 7
- 标签
- (无)
- 递交数
- 27
- 已通过
- 7
- 上传者