Codeforces Round #701 (Div.2)

contest

A. Add and Divide

不难想到,最优解一定是\(b\)先加到某个值\(b'\)后再通过不断除而成。

答案即为\(\min \{n + \left \lfloor \log_{b + n} {a} \right \rfloor + 1\}\)\(n\)\(b\)加了几次。
可以想出答案不会超过\(30\),枚举\(n\)即可。

# include <bits/stdc++.h>
using namespace std;
int t;
int a,b;
 
int qfind(int a,int b)
{
    long long cur = 1;
    if(a == 1) return 1;
    if(b == 1) return 1e9 + 7;
    for(int i = 1; i <= 31; i++)
    {
        cur *= b;
        if(cur > a) return i;
        else if(cur == a) return i + 1;
    }
}
 
int main(void)
{
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&a,&b);
        if(a < b)
        {
            printf("1\n");
            continue;
        }
        if(a == b)
        {
            printf("2\n");
            continue;
        }
        int ans = 31;
        for(int n = 0; n <= 30; n++)
        {
            int P = qfind(a,b + n);
            ans = min(ans,P + n);
            // printf("n = %lld,b + n = %lld,P = %lld\n",n,b + n,P);
        }
        printf("%d\n",ans);
    }
    return 0;
}

B. Replace and Keep Sorted

考虑对于第\(i\)个位置上可以改成几个数是合法的。

  • 对于\(i = 1\),则整数\(x\)满足\(x \in [1,a_2)\)是合法的。
  • 对于\(i = n\),则整数\(x\)满足\(x \in (a_{n - 1},k]\)是合法的。
  • 对于\(1 < i < n\),则整数\(x\)满足\(x \in (a_{i - 1},a_{i + 1})\)是合法的。
    \(b_i\)为第\(i\)个位置上能够修改的数的个数,减一下就珂以了,别忘了减一(不能和\(a_i\)一样)
    然后\(sum_i\)维护一下\(b_i\)前缀和,对于每个询问\(l_i,r_i\),答案为\(Sum(l_i + 1,r_i - 1)\)再加上两边的个数,因为两边不受限制了。
# include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
int n,q,k;
int a[N];
int b[N];
long long sum[N];

int Get1(int l,int r)
{
    if(l > r) return 0;
    return r - l + 1;
}

long long Get2(int l,int r)
{
    return sum[r] - sum[l - 1];
}

int main(void)
{
    scanf("%d%d%d",&n,&q,&k);
    for(int i = 1; i <= n; i++)
    {
        scanf("%d",&a[i]);
    }
    for(int i = 1; i <= n; i++)
    {
        if(i == 1)
        {
            b[i] = Get1(1,a[i + 1] - 1);
        }
        else
        {
            if(i == n)
            {
                b[i] = Get1(a[i - 1] + 1,k);
            }
            else b[i] = Get1(a[i - 1] + 1,a[i + 1] - 1);
        }
        --b[i];
        // printf("b[%d] = %d\n",i,b[i]);
    }
    for(int i = 1; i <= n; i++) sum[i] = sum[i - 1] + b[i];
    while(q--)
    {
        int l,r;
        scanf("%d%d",&l,&r);
        if(l == r)
        {
            printf("%d\n",k - 1);
            continue;
        }
        if(l + 1 == r)
        {
            long long ans = Get1(1,a[r] - 1) - 1 + Get1(a[l] + 1,k) - 1;
            printf("%lld\n",ans);
            continue;
        }
        long long ans = Get2(l + 1,r - 1);
        ans += Get1(1,a[l + 1] - 1) - 1;
        ans += Get1(a[r - 1] + 1,k) - 1;
        printf("%lld\n",ans);

    }
    return 0;
}

C. Floor and Mod

这题有点恶心,虽然只有*1700。
考虑固定住\(b\)
很容易想到\(\left \lfloor \frac{a}{b} \right \rfloor\)的答案是一块一块的,然后就会联想到:
对于\(a \in [1,b),\left \lfloor \frac{a}{b} \right \rfloor = 0\)
对于\(a \in [b,2b),\left \lfloor \frac{a}{b} \right \rfloor = 1\)
对于\(a \in [2b,3b),\left \lfloor \frac{a}{b} \right \rfloor = 2\)
\(\cdots\)
对于\(a \in [(k - 1)b,kb),\left \lfloor \frac{a}{b} \right \rfloor = k - 1 \space (k \le b)\)
然后我们会发现,除了第一组,其它每一组对答案都有\(1\)的贡献。
对于第\(k\)块,对答案有贡献(即\(\left \lfloor \frac{a}{b} \right \rfloor = a \bmod b\))的\(a_k = (k - 1)b + k - 1 = (k - 1)(b + 1)\)。同时\(a\)还得要满足\(a \le x\)的性质,而我们的目标,就是找到最大的这个\(k\),然后对于每一个\(b\),求出其最大值\(k\),其对答案贡献为\(k - 1\)
考虑对于每个\(b\)如何求出\(k\)最大值。
根据上面的东西列不等式:

\[\begin{aligned} (k - 1)(b + 1) &\le x\\ k - 1 &\le \dfrac{x}{b + 1}\\ k &\le \dfrac{x}{b + 1} + 1\\ \end{aligned} \]

然后取个整即可。不过要和\(b\)\(\min\)

通过分析,我们发现我们要求

\[\sum_{b = 1} ^ y \min \left(\left \lfloor \dfrac{x}{b + 1} \right \rfloor,b - 1 \right) \]

单次询问复杂度\(\mathcal{O}(b)\),然而\(b \le 10^9\)

我们发现了下取整符号,考虑分块,但是得先把\(\min\)去掉。
列不等式

\[\begin{aligned} b - 1 &\le \dfrac{x}{b + 1}\\ (b - 1)(b + 1) &\le x\\ b^2 - 1 &\le x\\ b^2 &\le x + 1\\ b &\le \sqrt{x + 1}\\ \end{aligned} \]

对于\([1,\sqrt{x + 1}]\)直接等差数列求和,对于\([\sqrt{x + 1} + 1,y]\)使用数论分块。

# include <bits/stdc++.h>

using namespace std;
int t;
long long x,y;

# define min(x,y) x < y ? x : y

long long solve(void)
{
    long long ans = 0;
    bool flag = 0;
    for(int b = 1; b <= y; b++)
    {
        ans += min(b - 1,int(x / (b + 1)));
        if(b - 1 > x / (b + 1) && !flag) 
        {
            printf("flag = %d\n",b);
            flag = 1;
        }
    }
    return ans;
}

long long dc(int l,int r)
{
    return (l + r) * (r - l + 1) / 2;
}

long long solve2(void)
{
    long long ans = 0;
    int SQ = int(sqrt(x + 1));
    ans = dc(0,min(SQ - 1,y - 1)); // [1,SQ]
    // printf("SQ = %d\n",SQ
    for(int l = SQ + 2,r = 0; l <= y + 1; l = r + 1)
    {
        int s = x / l;
        if(!s) break;
        r = min(x / s,y + 1);
        ans += (r - l + 1) * s;
    }
    return ans;
}

int main(void)
{
    scanf("%d",&t);
    while(t--)
    {
        scanf("%lld%lld",&x,&y);
        printf("%lld\n",solve2());
    }
    return 0;

}

D. Multiples and Power Differences

构造题。
\(i + j\)为偶,填\(720720\)
\(i + j\)为奇,填\(720720 + a_{i,j}^4\)

E. Move and Swap

# include <bits/stdc++.h>

using namespace std;

const int N = 2e5 + 5;

int t;
int n;
long long a[N],dp[N];

vector <int> g[N],G[N];
int f[N],dep[N];

const long long inf = 1e10;

// # define max(a,b) a > b ? a : b

int d;

void dfs(int x,int fa)
{
    G[dep[x]].push_back(x);
    d = max(d,dep[x]);
    for(int i = 0; i < (int)g[x].size(); i++)
    {
        int v = g[x][i];
        if(v != fa)
        {
            f[v] = x;
            dep[v] = dep[x] + 1;
            dfs(v,x);
        }
    }
    return;
}

int main(void)
{
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        for(int i = 1; i <= n; i++)
        {
            dep[i] = 0;
            f[i] = 0;
            G[i].clear();
            g[i].clear();
            dp[i] = 0;
        }
        for(int i = 2; i <= n; i++)
        {
            int v;
            scanf("%d",&v);
            g[i].push_back(v);
            g[v].push_back(i);
        }
        for(int i = 2; i <= n; i++)
        {
            scanf("%lld",&a[i]);
        }
        dep[1] = 0;
        dfs(1,0);
        // printf("d = %d\n",d);
        // // dp[0] = 0;
        // for(int i = 1; i <= n; i++)
        // {
        //     printf("dep[%d] = %d\n",i,dep[i]);
        // }
        // putchar('\n');
        for(int i = 1; i <= d; i++)
        {
            long long Max = -inf,Min = inf,Max1 = -inf,Max2 = -inf;
            for(int j = 0; j < (int)G[i].size(); j++)
            {
                int v = G[i][j];
                Max = max(Max,a[v]);
                Min = min(Min,a[v]);
                Max1 = max(Max1,a[v] + dp[f[v]]);
                Max2 = max(Max2,dp[f[v]] - a[v]);
            }
            // printf("i = %d,Max = %lld,Min = %lld,Max1 = %lld,Max2 = %lld\n",i,Max,Min,Max1,Max2);
            for(int j = 0; j < (int)G[i].size(); j++)
            {
                int v = G[i][j];
                dp[v] = max(abs(Min - a[v]),abs(Max - a[v])) + dp[f[v]];
                dp[v] = max(dp[v],max(Max1 - a[v],Max2 + a[v]));
            }
        }
        long long ans = 0;
        for(int i = 1; i <= n; i++)
        {
            ans = max(ans,dp[i]);
        }
        printf("%lld\n",ans);
    }
    return 0;

}

posted @ 2021-02-13 16:41  luyiming123  阅读(130)  评论(0编辑  收藏  举报