前言
C ±1 Operation 1
t
a
g
:
tag :
tag:等差数列
分类讨论
数学分析
题意 :
给定
x
,
a
,
d
,
n
x,a,d,n
x,a,d,n你可以对
x
x
x进行操作,询问最少多少次数使得
a
,
d
,
n
a,d,n
a,d,n表示的等差数列中的某一项正好等于
x
x
x
a
,
d
,
n
a,d,n
a,d,n表示 首项
a
a
a,
d
d
d公差,
n
n
n表示项数
思路 :
显然这个数是个定值,并且这题需要分类讨论
首先对 d d d进行讨论,我们发现如果 d < 0 d<0 d<0我们可以将得到的等差数列进行反转变成 d > 0 d>0 d>0的情况,所以我们只需要考虑 d > 0 d>0 d>0的情况
然后显然 x < a 1 ∣ ∣ x > a n x<a_1||x>a_n x<a1∣∣x>an的值肯定是两边的最小
而中间的,我们只需要通过等差数列公式变形一下即可
code :
ll x,a,d,n;
void solve(){
cin>>x>>a>>d>>n;
ll _an = a + (n-1) * d;
if(d < 0 ){
swap(_an,a);
d = -d;
}
if(x > _an) cout<<abs(x - _an)<<endl;
else if(x < a) cout<<abs(a - x)<<endl;
else{
if(!d) cout<<0<<endl;
else{
ll t = (x - a)%d;
cout<<min(t,d-t)<<endl;
}
}
}
D ±1 Operation 2
t
a
g
:
tag :
tag: 数学分析
前缀和
二分
题意
先run了
思路 :
显然这个答案也是固定的,但是我们并不能
O
(
n
q
)
O(nq)
O(nq)的去做
但是我们可以利用操作对数组进行分类
即需要减少的和需要增加的
我们通过 前缀和累积贡献,然后使用二分计算分割点即可
code :
ll n,q;
ll a[N],s[N];
ll x;
void solve(){
cin>>n>>q;
for(int i=1;i<=n;i++) cin>>a[i];
sort(a+1,a+1+n);
for(int i=1;i<=n;i++) s[i] = s[i-1] + a[i];
while(q -- ){
cin>>x;
int l = lower_bound(a+1,a+1+n,x) - a ;
int r = lower_bound(a+1,a+1+n,x) - a ;
ll res = 0 ;
l -- ;
r -- ;
//cout<<(x*l - s[l])<<endl;
//cout<<(s[n] - s[r] -(n-r) * x)<<endl;
res = (x * l - s[l] ) + (s[n] - s[r] - (n - r)*x );
cout<<res<<endl;
}
}
int main(){
//int t;cin>>t;while(t--)
solve();
return 0 ;
}