AtCoder Beginner Contest 255「C 二分」「D 前缀和」「E」

C - ±1 Operation 1

题目描述:

给你一个等差数列,首项为A,公差为D,项数为N,问X和这N项中数字差的绝对值最小为多少

思路:

二分一下,找到离他最近的两项,求一个最小值就行

注意公差可能为负数,所以可以分情况讨论,或者可以将这N个数倒着看就成了公差为正数的一个等差数列

注意,如果二分的后找到大于等于x的位置是第一项或者第n+1项,那答案就只由一个数决定,否则是取左右两个的最小值,要特判一下

#include 
using namespace std;

#define endl '\n'
#define inf 0x3f3f3f3f
#define mod7 1000000007
#define mod9 998244353
#define m_p(a,b) make_pair(a, b)
#define mem(a,b) memset((a),(b),sizeof(a))
#define io ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
#define debug(a) cout << "Debuging...|" << #a << ": " << a << "\n";
typedef long long ll;
typedef pair <int,int> pii;

#define MAX 300000 + 50
ll n, a, d, x;

ll f(ll n){
    return a + (n - 1) * d;
}

void work(){
    cin >> x >> a >> d >> n;
    ll l = 1, r = n;
    while(l <= r){
        ll mid = (l + r) / 2;
        if(d >= 0){
            if(f(mid) > x)r = mid - 1;
            else if(f(mid) < x)l = mid + 1;
            else {
                cout << 0 << endl;
                return;
            }
        }
        else{
            if(f(mid) < x)r = mid - 1;
            else if(f(mid) > x)l = mid + 1;
            else {
                cout << 0 << endl;
                return;
            }
        }
    }
    if(d >= 0){
        ll id = l - 1;
        if(!id)cout << a - x << endl;
        else if(id == n)cout << x - f(n) << endl;
        else{
            cout << min(x - f(id), f(id + 1) - x) << endl;
        }
    }
    else{
        ll id = r + 1;
        if(id == 1)cout << x - a << endl;
        else if(id == n + 1)cout << f(n) - x << endl;
        else{
            cout << min(f(id - 1) - x, x - f(id)) << endl;
        }
    }
}


int main(){
    io;
    work();
    return 0;
}

D - ±1 Operation 2

题目描述:

给你数列A,若干次询问,每次询问都是问一个数字X,你可以对数列中任意一个数进行若干次加一或减一的操作,问将数组A的数字全部变成X需要多少次操作

思路:

排序后维护一个前缀和,对于每个X,我们将数组分成都小于X的数和都大于等于X的数,分别对这两部分求答案,这只需要知道数字个数和数字和即可,所以要维护一个前缀和

#include 
using namespace std;

#define endl '\n'
#define inf 0x3f3f3f3f
#define mod7 1000000007
#define mod9 998244353
#define m_p(a,b) make_pair(a, b)
#define mem(a,b) memset((a),(b),sizeof(a))
#define io ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
#define debug(a) cout << "Debuging...|" << #a << ": " << a << "\n";
typedef long long ll;
typedef pair <int,int> pii;

#define MAX 300000 + 50
ll n, m, k, x;
ll tr[MAX];
ll sum[MAX];

ll getsum(ll l, ll r){
    return sum[r] - sum[l - 1];
}

void work(){
    cin >> n >> m;
    for(int i = 1; i <= n; ++i)cin >> tr[i];
    sort(tr + 1, tr + 1 + n);
    for(int i = 1; i <= n; ++i)sum[i] = sum[i - 1] + tr[i];
    tr[n + 1] = 1e18;
    for(int i = 1; i <= m; ++i){
        cin >> x;
        ll id = upper_bound(tr + 1, tr + 2 + n, x) - tr;
        if(id == 1 || id == n + 1){
            cout << abs(n * x - getsum(1, n)) << endl;
        }
        else{
            cout << (id - 1) * x - getsum(1, id - 1) + getsum(id, n) - (n - id + 1) * x << endl;
        }
    }
}


int main(){
    io;
    work();
    return 0;
}

E - Lucky Numbers

题目描述:

给你N-1个数字S[i],以及M个数字X[i],现在定义数组A满足A[i] + A[i + 1] = S[i],i=1,2,...,N-1,问当M个数字在数组A中出现次数最多的时候是多少个

思路:

不难发现,当A[1]固定以后,数组A就固定了,所以我们要想办法把A[i]A[1]表示出来

A[2] = S[1] - A[1]

A[3] = S[2] - A[2] = S[2] - S[1] + A[1]

A[4] = S[3] - A[3] = S[3] - S[2] + S[1] - A[1]

我们设B[i] = S[i] - B[i], i >= 2, B[1] = 0

所以 A [ i ] = B [ i ] + ( − 1 ) i + 1 ∗ A [ 1 ] A[i] = B[i] + (-1)^{i+1}*A[1] A[i]=B[i]+(1)i+1A[1]

我们把A[1]分离出来,可以得到 A [ 1 ] = ( − 1 ) i + 1 ∗ ( A [ i ] − B [ i ] ) A[1] = (-1)^{i+1}* (A[i] - B[i]) A[1]=(1)i+1(A[i]B[i])

因为我们想要的是A[i] = X[j],所以我们对于每个i,枚举每个X[j],计算出要想A[i] = X[j]A[1]的值,我们用map存一下数量,最后跑一遍map,找到第二键值最大的输出,记得开longlong

#include 
using namespace std;

#define endl '\n'
#define inf 0x3f3f3f3f
#define mod7 1000000007
#define mod9 998244353
#define m_p(a,b) make_pair(a, b)
#define mem(a,b) memset((a),(b),sizeof(a))
#define io ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
#define debug(a) cout << "Debuging...|" << #a << ": " << a << "\n";
typedef long long ll;
typedef pair <int,int> pii;

#define MAX 300000 + 50
ll n, m, k, x;
ll s[MAX];
ll br[MAX];

void work(){
    cin >> n >> m;
    for(int i = 1; i < n; ++i){
        cin >> s[i];
    }
    for(int i = 2; i <= n; ++i){
        br[i] = s[i - 1] - br[i - 1];
    }
    map<ll, ll>mp;
    for(int j = 1; j <= m; ++j){
        cin >> x;
        for(int i = 1; i <= n; ++i){
            ++mp[(x - br[i]) * (i % 2 == 0 ? -1 : 1)];
        }
    }
    ll ans = 0;
    for(auto [x, y] : mp)ans = max(ans, y);
    cout << ans << endl;
}


int main(){
    io;
    work();
    return 0;
}

你可能感兴趣的:(Atcoder,c++,算法,二分,数论)