• Educational Codeforces Round 83 (Rated for Div. 2)


    题目链接:https://codeforces.com/contest/1312

    A - Two Regular Polygons

    送分题。

    B - Bogosort

    题意:给一个数组a进行重排,使得新的数组a中,记b[i]=a[i]-i,则b[i]是唯一的。

    题解:从大到小排序,这样就有b[i+1]=a[i+1]-(i+1)<a[i+1]-i<=a[i]-i<b[i]。

    C - Adding Powers

    题意:给一个n个数的数组b,另一个n个数的数组a初始全是0,第i步(i从0开始计数)可以选择数组a中的一个数加上k^i,或者跳过这一步,问是否能把数组a变成数组b。

    题解:对每个数进行k进制分解,看看是否k进制下每一位的和都是<=1的。

    D - Count the Arrays

    可以初步观察出一些事实:
    1、最大的数是只有一个的,否则不会满足左右都是严格升降序。
    2、最大的数的取值范围为 ([n-1,m])
    3、最大的数不能放在两端。
    4、相等的数分布在最大的数两侧。

    算法1,给位置选数

    先枚举最大的数的位置,设其前面有 (x) 个位置,后面有 (y) 个位置,则 (xge 0,y ge 0,x+y=n-1)
    再枚举最大的数的取值,观察可以发现最大的数的取值是不受位置影响的,设取值为 (p in [n-1,m])
    再从 ([1,p-1]) 中选 (x) 个数给前面 (x) 个位置,选法为 (C_{p-1}^{x})
    再从前面 (x) 个数中选 (1) 个数作为相等的数字放在后面的某个位置, 选法为 (C_{x}^{1})
    再从 ([1,p-1]) 个数中选 (y-1) 个数给后面剩下的 (y-1) 个位置,且这些数不能与前面 (x) 个数相等,选法为 (C_{p-1-x}^{y-1})

    这里会发现复杂度爆炸,但是这个形式看起来有规律。

    [egin{align} &C_{p-1}^{x}*C_{x}^{1}*C_{p-1-x}^{y-1} onumber \ &=frac{(p-1)!}{(p-1-x)!x!}*x*frac{(p-1-x)!}{(p-1-x-(y-1))!(y-1)!} onumber \ &=frac{(p-1)!}{(p-n+1)!(x-1)!(y-1)!} onumber \ &=frac{1}{(x-1)!(y-1)!}*frac{(p-1)!}{(p-n+1)!} onumber \ end{align} ]

    后面的部分与 (x,y) 无关,前面的部分与 (p) 无关,两部分可以分开统计了。

    算法2,给数选位置

    先从 ([1,m]) 中选出 (n-1) 个数,然后可以把他们离散化到 ([1,n-1])
    然后从 ([1,n-2]) 中选出那个相等的数(因为 (n-1) 是最大的数,不能相等),放在最大的数两边。
    剩下的数既可以放在左边,也可以放在右边,有 (2^{n-3}) 种选法。

    反思:怪不得这道题这么多人过,算法2是真的简单,所以以后组合数学可以从“给位置选数”以及“给数选位置”两种角度考虑。

    关键是得知了: (C_{n}^{x}*C_{n-x}^{y} e C_{n}^{x+y}) 而是 (C_{n}^{x}*C_{n-x}^{y} e C_{n}^{x+y}*C_{x+y}^{x}) ,也就是说,等式左侧的规定了哪些数是去 (x) 中的,所以在等式右侧也要规定。

    *E - Array Shrinking

    第一次见区间dp可以这样做的。以前的区间dp貌似都是枚举“最后一次合并区间时发生的状态转移”,但这里的两个区间合并的时候要保证“左右的剩下元素的左右边界相同”。这里就发现自己是没真正明白区间dp的。枚举的是“最后一次合并区间时发生的状态转移”,所以必须是“最后一次合并区间”,换言之,假如枚举的区间是[5 4 3 3][3 3 4 5],回答的就应该是[7],为什么不用考虑下面的[3 3]或者3][3合并呢?因为这些合并应该在长度更小(长度为2)的时候被处理完,并不是“最后一次合并区间”。换言之,在枚举断点,合并左右两端的时候,只需要知道两点:

    1、左区间和右区间是否分别能合并成一个数,使得枚举断点的位置确实成为“最后一次合并”。

    2、左区间和右区间能合并成的一个数是否相同,使得枚举断点的位置确实成为“最后一次合并”。

    int a[505];
    int b[505][505];
    int dp[505][505];
    
    void test_case() {
        int n;
        scanf("%d", &n);
        for(int i = 1; i <= n; ++i)
            scanf("%d", &a[i]);
        for(int i = 1; i <= n; ++i) {
            for(int j = 1; j <= n; ++j) {
                dp[i][j] = INF;
                b[i][j] = 0;
            }
        }
        for(int i = 1; i <= n; ++i) {
            dp[i][i] = 1;
            b[i][i] = a[i];
        }
        for(int len = 2; len <= n; ++len) {
            for(int l = 1; l <= n; ++l) {
                int r = l + len - 1;
                if(r > n)
                    break;
                for(int m = l; m < r; ++m) {
                    dp[l][r] = min(dp[l][r], dp[l][m] + dp[m + 1][r]);
                    if(b[l][m] != 0 && b[l][m] == b[m + 1][r]) {
                        dp[l][r] = 1;
                        b[l][r] = b[l][m] + 1;
                        break;
                    }
                }
            }
        }
        printf("%d
    ", dp[1][n]);
    }
    

    总结:其实就是短的合并都已经被下层枚举了,比如[5 4 3 3 3 3 4 5],假如要问[4 3 3]是否可以合并成一个数,就向下询问[4][3 3]是否可以分别合并成一个数,且这两个数相等(并不需要事先知道要合并成几,因为每个区间完全合并得到的数是唯一的,dfs得到左边之后询问右边即可),再问[4 3][3]行不行,以此类推。

  • 相关阅读:
    2016"百度之星"
    codeforces 55 div2 C.Title 模拟
    codeforces 98 div2 C.History 水题
    codeforces 97 div2 C.Replacement 水题
    codeforces 200 div2 C. Rational Resistance 思路题
    bzoj 2226 LCMSum 欧拉函数
    hdu 1163 九余数定理
    51nod 1225 余数的和 数学
    bzoj 2818 gcd 线性欧拉函数
    Codeforces Round #332 (Div. 2)D. Spongebob and Squares 数学
  • 原文地址:https://www.cnblogs.com/KisekiPurin2019/p/12452921.html
Copyright © 2020-2023  润新知