• Codeforces Round #701 (Div. 2) A~C 题解


    写在前边

    链接:Codeforces Round #701 (Div. 2)
    数学场,题目描述简单粗暴,思路很妙,代码短的不行,都是好神奇的一些题目。

    A. Add and Divide

    链接:A题链接

    题目大意:

    给定两个正整数,我们可以进行两个操作:

    • (a = lfloor frac{a}{b} floor)
    • (b = b + 1)
      最终目标是找到使(a)变成(0)的最小操作次数

    思路

    因为(b)每次只会变动(1),所以最开始思路就是,如果我们可以提前大体找到一个操作次数,我们在这个操作次数内进行枚举,而(b)每次操作只会变动(1),所以假设一共有(sum)次操作,如果我们可以有(n)次让(b)(1),然后(b)变成了(b + n),然后让(a)不断的除(b)直到为(0),假设有(m)次操作,那么答案就是(m + n)次操作了,那么怎么才能找到这个(sum)呢,可以看数据范围,我们可以估计最差的情况,最差的情况就是当(b=1,a = 10^9)的时候,这时候我们首先要做的就是让(b + 1),然后再让(a)不断的除(b),直到为(0),而这最多需要(lfloor log_2(10^9) floor = 29)次,所以!经过分析最差情况也就进行(30)次操作左右,即(m + n < 31)所以我们只需要枚举到(31)即可,最坏情况(O(log^2a))

    代码:

    #include <iostream>
    
    #include <cstring>
    #include <algorithm>
    #include <cstdio>
    #include <vector>
    #include <map>
    #include <cstring>
    
    using namespace std;
    
    #define Inf 0x3f3f3f3f
    #define PII pair<int, int>
    #define P2LL pair<long long, long long>
    #define endl '
    '
    
    typedef long long LL;
    typedef unsigned long long ULL;
    typedef vector<long long> VLL;
    typedef vector<int> VI;
    
    void solve() {
        int a, b, res = 35;
        cin >> a >> b;
        if (a < b) {
            puts("1");
            return;
        }
    
        for (int i = (b == 1 ? 1 : 0); i <= 30; i++) { //枚举多少次 最坏情况下就有30次
            int tempa = a, tempres = i;
            int tempb = b + i;
            
            while (tempa) {
                tempa /= tempb;
                tempres++;  
            }
            res = min(res, tempres);
        }
    
        cout << res << endl;
    }
    
    int main()
    {
        //ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
        int t;
        scanf("%d", &t); 
        while (t--) {
            solve();
        }
        system("pause");
        return 0;
    }
    

    B. Replace and Keep Sorted

    链接:B题链接

    题目大意:

    定义两个互为(k-similar)的数组:

    • 都是严格单调递增
    • 有相同的长度
    • 它们的元素范围(in [1, k])
    • 它们只有一个数不同。

    现在给定一个数组(a),并且给定一个区间([l,r]),那么(k-similar)中的一个数组(b_1)就是([a_l, a_{l + 1}, ... , a_r]),长度为(len = l - r + 1) 那么另一个(k-similar)数组(b_2)就是可以从([1, k])中选(len)个数,并且只与(b_1)有一个数不同的数组,问有多少个这样的数组(b_2)

    思路

    首先想到可以挨个枚举每一个位置可以选多少个数,那么最终答案就是每一个位置可以选的数之和,但是这样数据范围就是(O(q*n))明显会超时,所以就想能不能在(O(1))复杂度之内就能判断出一个区间中所有的可能,第(l)个位置的数可以选(a[l + 1] - 2)个,第(r)个位置的数可以选(k - a[r - 1] - 1)个,对于((l,r))(注意是开区间!)能选多少个我们可以用前缀和处理,前缀和就是每一个区间可以选择的数的个数,时间复杂度就降为了(O(q)).

    代码:

    #include <iostream>
    #include <cstring>
    #include <algorithm>
    #include <cstdio>
    #include <vector>
    #include <map>
    #include <cstring>
    
    using namespace std;
    
    #define Inf 0x3f3f3f3f
    #define PII pair<int, int>
    #define P2LL pair<long long, long long>
    #define endl '
    '
    
    typedef long long LL;
    typedef unsigned long long ULL;
    typedef vector<long long> VLL;
    typedef vector<int> VI;
    
    const int N = 1e5 + 10;
    int a[N], b[N];
    
    void solve() {
        int n, k, q;
        scanf("%d%d%d", &n, &q, &k);
        for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
    
        a[n + 1] = k + 1;
        for (int i = 1; i <= n; i++) {
            b[i] += a[i + 1] - a[i - 1] - 2;
            b[i] += b[i - 1];
        }
    
        while (q--) {
            LL res = 0;
            int l, r;
            scanf("%d%d", &l, &r);
            res += b[r - 1] - b[l];  //开区间
            res += k - a[r - 1] - 1; //右边    
            res += a[l + 1] - 2; //左边
            printf("%d
    ", res);
        }
    }
    
    int main()
    {
        //ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
        solve();
    
        return 0;
    }
    

    C. Floor and Mod

    链接:C题链接

    题目大意:

    给定下下(x,y),现在要求求一个数对((a, b)),使得(lfloor frac{a}{b} floor = a \,\, mod \,\, b), 要求(a in [1, x]), (b in [1, y])

    思路

    首先暴力肯定不行,所以想能不能用(O(1))直接求出来,那只要推公式了,让(lfloor frac{a}{b} floor = a \,\, mod \,\, b = k),所以推出(a = k*b + k(b > k)),又因为(b > k),可以推出(k^2 < k*b+k = a leq x),所以(k leq sqrt{x}),所以现在求出了(k)的范围(k in [1, sqrt{x}\,]),现在要做的就是对于每一个固定的(k),如果我们可以推出(a)或者(b)数的范围,那么就可以求出数对((a, b))可取的个数了,对于b,已知(b > k), (1 geq b leq y),根据 (k*b+k = a leq x),得出(b leq x / k - 1),因此得出(b)的个数就是(max(0, min(y, x / k - 1) - k))

    代码:

    #include <iostream>
    #include <cstring>
    #include <algorithm>
    #include <cstdio>
    #include <vector>
    #include <map>
    #include <cstring>
    
    using namespace std;
    
    #define Inf 0x3f3f3f3f
    #define PII pair<int, int>
    #define P2LL pair<long long, long long>
    #define endl '
    '
    
    typedef long long LL;
    typedef unsigned long long ULL;
    typedef vector<long long> VLL;
    typedef vector<int> VI;
    
    void solve() {
        LL x, y;
        cin >> x >> y;
    
        LL res = 0;
        for (LL k = 1; k * k <= x; k++) {
            res += max(0LL, min(y, x / k - 1) - k);
        }
    
        cout << res << endl;
    }
    
    int main()
    {
        //ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
        int t;
        scanf("%d", &t); 
        while (t--) {
            solve();
        }
        system("pause");
        return 0;
    }
    
  • 相关阅读:
    XAML
    诺基亚Lumia 800越狱教程
    Windows Phone常用控件
    Windows Phone数据存储
    Silverlight自定义鼠标
    [silverlight] silverlight3新增功能1:三维效果(透视转换)
    [silverlight] silverlight3新增功能2:WriteableBitmap
    另一种方法实现silverlight图片局部放大效果
    [Silverlight]简单实现DataGrid使用CheckBox选择行
    好用的模糊搜索下拉提示
  • 原文地址:https://www.cnblogs.com/ZhengLijie/p/14402262.html
Copyright © 2020-2023  润新知