ARC100 部分题解
作者:互联网
C:
转化一下就是取中间部位,绝对值之和最小
// by Balloons
#include <cstdio>
#include <vector>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
#define mpr make_pair
#define debug() cerr<<"Madoka"<<endl
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
using namespace std;
typedef long long LL;
const int inf = 1e9, INF = 0x3f3f3f3f, maxn=2e5+5;
int n,a[maxn];
signed main(){
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&a[i]), a[i] -= i;
sort(a+1, a+n+1);
if(n == 1)return puts("0"), 0;
int tmp = n/2, tmp2 = n/2+1;
LL res1=0, res2=0;
tmp = a[tmp], tmp2 = a[tmp2];
for(int i=1;i<=n;i++)res1 += abs(a[i] - tmp);
for(int i=1;i<=n;i++)res2 += abs(a[i] - tmp2);
printf("%lld\n",min(res1, res2));
return 0;
}
D
枚举中间的断点,感受一下可以发现答案最小则一定两边的答案最小
二分两边的差,再二分求出对应的第一、三个断点的位置来判断是否存在,2个log
// by Balloons
#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
#define mpr make_pair
#define debug() cerr<<"Madoka"<<endl
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
using namespace std;
typedef long long LL;
#define int LL
const int inf = 1e9, INF = 0x3f3f3f3f, maxn=2e5+5;
int n,a[maxn], sum[maxn];
int getsum(int l,int r){return sum[r] - sum[l-1];}
int check(int x,int lim){
int s1 = getsum(1, x);
int l = 1, r = x, lf1, lf2;
while(l <= r){
int mid = l+r>>1;
if(getsum(mid, r) >= (s1 - lim)/2)lf1 = mid, l = mid+1;
else r = mid-1;
}
l = 1, r = x;
while(l <= r){
int mid = l+r>>1;
if(getsum(mid, r) <= (s1 + lim)/2)lf2 = mid, r = mid-1;
else l = mid+1;
}
if(lf1 > lf2)return 0;
debug();
int s2 = getsum(x+1, n);
l = x+1, r = n;
int ri1, ri2;
while(l <= r){
int mid = l+r>>1;
if(getsum(mid, n) >= (s2 - lim)/2)ri1 = mid, l = mid+1;
else r = mid-1;
}
l = x+1, r = n;
while(l <= r){
int mid = l+r>>1;
if(getsum(mid, n) <= (s2 + lim)/2)ri2 = mid, r = mid-1;
else l = mid+1;
}
if(ri1 > ri2)return 0;
return 1;
}
signed main(){
cin >> n;
for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
for(int i=1;i<=n;i++)sum[i] = sum[i-1] + a[i];
int r = 1e15;
printf("%d\n",check(2,2));
for(int i = 2;i<=n-2;i++){
int l = 0, r = 1e15, ans;
while(l <= r){
int mid = l+r>>1;
if(check(i, mid))r = mid-1, ans = mid;
else l = mid+1;
}
r = min(r, ans);
}
cout << r << endl;
return 0;
}
注意到随着中间断点往右挪,第一个断点肯定是不断往右的,因此我们就有了一个\(O(n)\)的算法
我这里面的p1[i]表示中间断点在(i,i+1)之间,左边的最小/大值,p2[i]同理
// by SkyRainWind
#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
#define mpr make_pair
#define debug() cerr<<"Madoka"<<endl
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
using namespace std;
typedef long long LL;
#define int LL
const int inf = 1e9, INF = 0x3f3f3f3f, maxn= 2e5 + 5;
int n;
int a[maxn];
pair<int,int>p1[maxn], p2[maxn];
signed main(){
scanf("%lld",&n);
for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
int now = 1;
LL sl = a[1], sr = a[2];
p1[2] = mpr(sl, sr);
for(int i=3;i<=n-2;i++){ // sl = a[1..now] sr = a[now+1..i]
sr += a[i];
while(now+1 < i && abs(sl - sr) > abs(sl + a[now+1] - (sr - a[now+1])))
sl += a[now+1], sr -= a[now+1], ++ now;
p1[i] = mpr(sl, sr);
}
now = n;
sl = a[n-1], sr = a[n];
p2[n-2] = mpr(sl, sr);
for(int i = n-2;i>=3;i--){
sl += a[i];
while(now-1 > i && abs(sl - sr) > abs(sl - a[now-1] - (sr + a[now-1])))
sl -= a[now-1], sr += a[now-1], -- now;
p2[i-1] = mpr(sl, sr);
}
int ans = 2e9;
for(int i=2;i<=n-2;i++){
int tt[] = {p1[i].first, p1[i].second, p2[i].first, p2[i].second};
sort(tt, tt+4);
ans = min(ans, tt[3] - tt[0]);
}
printf("%lld\n",ans);
return 0;
}
E
把下标\(x\)看成一个二进制集合
\(i|j \leq k\)一看就很前缀max
但是因为\(i | j \leq k\)不好处理,做一步转化:
只需要考虑\(i | j \in k\)的情况,做一个前缀max即可,显然这也是对的
考虑什么样的\(i, j\),k能被更新?显然是k为i和j的超集的时候,这显然是高维前缀和的经典应用(\(S \ xor\ (1<<k)==0\)的时候更新答案)
维护答案就记录一个最大值和次大值即可
// by SkyRainWind
#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
#define mpr make_pair
#define debug() cerr<<"Madoka"<<endl
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
using namespace std;
typedef long long LL;
const int inf = 1e9, INF = 0x3f3f3f3f;
int n;
int a[(1<< 18) + 5];
int mx[(1<< 18) + 5][2];
void ck(int x,int y){
int pp[] = {mx[x][0], mx[x][1], mx[y][0], mx[y][1]};
sort(pp,pp+4);
mx[x][0] = pp[3], mx[x][1] = pp[2];
}
signed main(){
scanf("%d",&n);
for(int i=0;i<=(1<<n) - 1;i++)scanf("%d",&a[i]), mx[i][0] = a[i], mx[i][1] = 0;
for(int k = 0;k<=n-1;k++)
for(int S = 0;S<=(1<<n)-1;S++)
if((S & (1<<k)) == 0){
ck(S ^ (1<<k), S);
}
int res = 0;
for(int i=1;i<=(1<<n) - 1;i++){
res = max(res, mx[i][0] + mx[i][1]);
printf("%d\n",res);
}
return 0;
}
标签:include,题解,mid,ARC100,sr,sl,now,部分,define 来源: https://www.cnblogs.com/SkyRainWind/p/16700739.html