Codeforces Round #757 (Div. 2) problem solution A-D2

Codeforces Round #757 (Div. 2)

A. Divan and a Store

analysis:

After sorting, you can be greedy from small to large.

code:

#include <bits/stdc++.h>
using namespace std;
//#pragma GCC optimize(2)
#define close(); 	ios::sync_with_stdio(false);
#define endl '\n'
#define rep(i, l, r) for(int i = l; i <= r; i++)
#define dwn(i, r, l) for(int i = r; i >= l; i--)
typedef long long LL;
const int N = 3e5+100;
int a[N];
void solve()
{
    int n, l, r, k; cin >>  n >> l >> r >> k;
    rep(i, 1, n) cin >> a[i];
    sort(a+1, a+1+n);
    int cnt = 0;
    rep(i, 1, n) 
    {
        if(a[i] >= l && a[i] <= r && k >= a[i]) k -= a[i], cnt++;
    }
    cout << cnt << endl;
}

int main()
{
    int T; cin >> T;
    while(T--) solve();
    // system("pause");
}

B. Divan and a New Project

analysis:

It is not difficult to observe that x 0 x_0 x0 , put it at the zero point (of course, other points are equivalent), and then greedily put it on both sides of the zero point

code:

#include <bits/stdc++.h>
using namespace std;
//#pragma GCC optimize(2)
#define close(); 	ios::sync_with_stdio(false);
#define endl '\n'
#define rep(i, l, r) for(int i = l; i <= r; i++)
#define dwn(i, r, l) for(int i = r; i >= l; i--)
typedef long long LL;
const int N = 1e6+100;

struct node{
    int idx;
    int w;
    bool operator<(const node& o) const{
        return w < o.w;
    }
};

node a[N];
int x[N];
void solve()
{
    int n; cin >> n;
    rep(i, 1, n) { cin >> a[i].w; a[i].w = -a[i].w; a[i].idx = i; }
    sort(a+1, a+1+n);
    int cnt = 1;
    LL ans = 0;
    rep(i, 1, n)
    {
        x[a[i].idx] = (i&1)?cnt:-(cnt++);
        ans += 2ll * abs(x[a[i].idx]) * (LL)(-a[i].w);
    }
    cout << ans << endl;
    rep(i, 0, n) cout << x[i] << " ";cout << endl;
}   

int main()
{
    close();
    int T; cin >> T;
    while(T--) solve();
    // system("pause");
}

C. Divan and bitwise operations

analysis:

At the beginning, I read the wrong question for nearly an hour. At first, I thought the given limit was interval XOR, and finally I found that the given limit was interval or

If it's an interval or, it's better to initialize all the elements to 0x7ffffff, and then use the restriction to the interval and, which is obviously the simplest condition to ensure the construction of an array that meets the restriction

Here I built a segment tree to maintain

Then consider how to calculate the answer after constructing an array that meets the limit?

Consider a bit by bit discussion c n t 1 cnt_1 cnt1 , represents the second in the binary representation i i i is the number of elements with Item 1, c n t 0 cnt_0 cnt0 ¢ is the opposite. Then the contribution of bit i to the answer is to select the number of schemes of odd elements with item i as 1 multiplied by 2 i 2^i 2i.

So there is the following formula:
A n s = ∑ i = 0 2 c n t 1 − 1 ⋅ 2 c n t 0 ⋅ 2 i Ans = \sum_{i=0} 2^{cnt_{1}-1} \cdot 2^{cnt_0} \cdot 2^i Ans=i=0∑​2cnt1​−1⋅2cnt0​⋅2i

code:

#include <bits/stdc++.h>
using namespace std;
//#pragma GCC optimize(2)
#define close(); 	ios::sync_with_stdio(false);
#define endl '\n'
#define rep(i, l, r) for(int i = l; i <= r; i++)
#define dwn(i, r, l) for(int i = r; i >= l; i--)
typedef long long LL;
#define lc (p<<1)
#define rc (lc|1)
#define mid ((l+r)>>1)
const int N = 2e5+100;
const int ALLONE = 0x7fffffff;
const LL p = 1e9+7;
int c[N<<2], lazy[N<<2];
int n;
int a[N];
void build(int p = 1, int l = 1, int r = n)
{
    if(l == r) c[p] = 0x7fffffff, lazy[p] = ALLONE;
    else {
        build(lc, l, mid);
        build(rc, mid+1, r);
        c[p] = 0x7fffffff;
        lazy[p] = ALLONE;
    }
}

void push(int p)
{
    c[lc] &= lazy[p];
    c[rc] &= lazy[p];
    lazy[lc] &= lazy[p];
    lazy[rc] &= lazy[p];
    lazy[p] = ALLONE;
}

void update(int tl, int tr, int x, int p=1, int l=1, int r=n)
{
    if(tl > r || tr < l ) return;
    else if(tl <= l && tr >= r) { c[p] &= x; lazy[p] &= x; return; }
    else 
    {
        push(p);
        update(tl, tr, x, lc, l, mid);
        update(tl, tr, x, rc, mid+1, r);
    }
}

void query(int p = 1, int l = 1, int r = n)
{
    if(l == r) a[l] = c[p];
    else {
        push(p);
        query(lc, l, mid);
        query(rc, mid+1, r);
    }
}

LL qpow(LL a, LL b)
{
    LL rev = 1;
    while(b)
    {
        if(b & 1) (rev *= a) %= p;
        a = a * a % p;
        b >>= 1;
    }
    return rev;
}



void solve()
{
    int m; cin >> n >> m;   
    build();
    rep(i, 1, m)
    {
        int l, r, x; cin >> l >> r >> x;
        update(l, r, x);
    }
    query();
    // rep(i, 1, n) cout << a[i] << " "; cout << endl;
    LL ans = 0;
    for(int k = 0; k < 30; k++)
    {
        int o, v; o = v = 0;
        for(int i = 1; i <= n; i++)
        {
            if(a[i] & (1<<k)) o++;
        }
        v = n-o;
        if(o > 0) (ans += qpow(2, o-1) * qpow(2, v) % p * (1<<k) % p) %= p;
    }
    cout << ans << endl;
}   

int main()
{
    close();
    int T; cin >> T;
    while(T--) solve();
    // system("pause");
}

D1. Divan and Kostomuksha (easy version)

analysis:

Consider dp

remember d p [ i ] dp[i] dp[i] denotes gcd as i i A group of numbers of i is the answer at the top. At this time, the order of this group of numbers is no matter, but it must be ahead of other numbers

remember b [ u ] b[u] b[u] represents the number of numbers containing factor U

According to the definition, it is not difficult to think of the transfer equation: $dp[i] = \max_{j|i} dp[i] + b[i] \cdot (i-j)$

Note that the maximum value of array x is C

So we can use the Ehrlich sieve, O ( C log ⁡ C ) O(C\log C) The dp of O(ClogC) completes all States

So how b b b array?

Considering that the time limit is 4s and n is only 1e5, direct violence can be calculated

So the final time complexity is O ( C log ⁡ C + n C ) O(C\log C + n \sqrt{C} ) O(ClogC+nC ​)

code:

#include <bits/stdc++.h>
using namespace std;
//#pragma GCC optimize(2)
#define close(); 	ios::sync_with_stdio(false);
#define endl '\n'
#define rep(i, l, r) for(int i = l; i <= r; i++)
#define dwn(i, r, l) for(int i = r; i >= l; i--)
typedef long long LL;
#define lc (p<<1)
#define rc (lc|1)
#define mid ((l+r)>>1)
typedef LL ll;
const int N = 2e5+100;
const LL p = 1e9+7;
const int MAXN = 5e6+100;
int a[N];
int b[MAXN];
LL dp[MAXN];
inline void div(int x)
{
    for(int i = 1; i*i <= x; ++i)
    {
        if(x%i==0)
        {
            b[i]++;
            if(i*i!=x) b[x/i]++;
        }
    }
}

void solve()
{
    int n; cin >> n;
    rep(i, 1, n) 
    {
        cin >> a[i];
        div(a[i]);
    }
    // rep(i, 1, 5000000) if(b[i]) cout << i << "-> " << b[i] << endl;
    LL ans = n;
    dp[1] = n;
    rep(i, 1, 5000000)
    {
        ans = max(ans, dp[i]);
        
        for(int j = 2; j*i <= 5000000; j++)
        {
            dp[i*j] = max(dp[i*j], dp[i] + ( b[i*j] ) * ( (LL)i*j-i ) );
        }

    }
    cout << ans << endl;
}   

int main()
{
    close();
    solve();
    // system("pause");
}

D2. Divan and Kostomuksha (hard version)

analysis:

Take the above code to try, D2 will be T, so consider further optimization.

remember d p [ i ] → d p [ j ] dp[i] \rightarrow dp[j] dp[i] → dp[j] indicates d p [ i ] dp[i] dp[i] update status d p [ j ] dp[j] dp[j]

From the definition point of view, we try to keep ranking the set of numbers with common factors in the front without distinction, and then continue to sort in the set of numbers with common factors according to the state transition (that is, the set of numbers with larger common factors in the front).

So obviously, for state transition, it is optimal to only transfer prime times each time.

More formally, d p [ i ] → d p [ j ] dp[i] \rightarrow dp[j] dp[i] → dp[j] will not be better than d p [ i ] → d p [ k ] → d p [ j ] dp[i] \rightarrow dp[k] \rightarrow dp[j] dp[i]→dp[k]→dp[j]

d p [ i ] → d p [ j ] dp[i] \rightarrow dp[j] dp[i] → dp[j] Yes d p [ j ] dp[j] The contribution of dp[j] is d p [ i ] + b [ j ] ⋅ ( j − i ) dp[i]+b[j]\cdot(j-i) dp[i]+b[j]⋅(j−i)

d p [ i ] → d p [ k ] → d p [ j ] dp[i] \rightarrow dp[k] \rightarrow dp[j] The contribution of dp[i] → dp[k] → dp[j] is $dp[i] + b[k]\cdot(k-i) + b[j]\cdot(j-k)$

be aware b [ j ] ≤ b [ k ] b[j] \le b[k] b[j]≤b[k]

Then there
d p [ i ] + b [ k ] ⋅ ( k − i ) + b [ j ] ⋅ ( j − k ) = d p [ i ] + ( b [ k ] − b [ j ] ) ⋅ ( k − i ) + b [ j ] ⋅ ( j − i ) ≥ d p [ i ] + b [ j ] ⋅ ( j − i ) dp[i] + b[k]\cdot(k-i) + b[j]\cdot(j-k) \\ = dp[i] + (b[k]-b[j]) \cdot (k-i) + b[j]\cdot(j-i) \\ \ge dp[i]+b[j]\cdot(j-i) dp[i]+b[k]⋅(k−i)+b[j]⋅(j−k)=dp[i]+(b[k]−b[j])⋅(k−i)+b[j]⋅(j−i)≥dp[i]+b[j]⋅(j−i)
So just sift the prime number through the Euler sieve

So the complexity of the algorithm is reduced to O ( C log ⁡ log ⁡ C + n C ) O(C\log\log C + n \sqrt{C} ) O(CloglogC+nC ​)

I felt that the complexity was still very metaphysical, so I paid a hard heart and passed it

code:

#include <bits/stdc++.h>
using namespace std;
//#pragma GCC optimize(2)
#define close(); 	ios::sync_with_stdio(false);
#define endl '\n'
#define rep(i, l, r) for(int i = l; i <= r; i++)
#define dwn(i, r, l) for(int i = r; i >= l; i--)
typedef long long LL;
#define lc (p<<1)
#define rc (lc|1)
#define mid ((l+r)>>1)
typedef LL ll;
const int N = 2e5+100;
const LL p = 1e9+7;
const int MAXN = 2e7+100;

bool isnp[MAXN];
vector<int> primes; // Prime number table
void init(int n)
{
    for (int i = 2; i <= n; i++)
    {
        if (!isnp[i])
            primes.push_back(i);
        for (int p : primes)
        {
            if (p * i > n)
                break;
            isnp[p * i] = 1;
            if (i % p == 0)
                break;
        }
    }
    isnp[1] = 1;
}

int a[N];
int b[MAXN];
LL dp[MAXN];
inline void div(int x)
{
    for(int i = 1; i*i <= x; ++i)
    {
        if(x%i==0)
        {
            b[i]++;
            if(i*i!=x) b[x/i]++;
        }
    }
}

void solve()
{
    int n; cin >> n;
    rep(i, 1, n) 
    {
        cin >> a[i];
        div(a[i]);
    }
    LL ans = n;
    dp[1] = n;
    rep(i, 1, 20000000)
    {
        ans = max(ans, dp[i]);
        
        for(int e: primes)
        {
            if(i * e > 20000000) break;
            dp[i*e] = max(dp[i*e], dp[i] + ( b[i*e] ) * ( (LL)i*e-i ) );
        }

    }
    cout << ans << endl;
}   

int main()
{
    close();
    init(20000000);
    solve();
    // system("pause");
}

Tags: C Algorithm

Posted on Sat, 27 Nov 2021 13:27:29 -0500 by TheStalker