• Codeforces Fifty-Seven


    水一篇打卡题的博客 

    1600 - C. Hard problem

    题目链接:https://codeforces.com/problemset/problem/706/C

    题意:

      给你长度为 N 的字符串数组,每个字符串可以进行翻转,翻转的代价为 Ci

      问要使字符串数组从 1~N 按字典序从小到大的最小代价为多少

    分析:

      简单 dp 。

      先转换一下题意:

      有一个长度为 n 的数组 A , 你可以花费 Ci 的代价使得 Ai → Bi

      现你要用最小的代价让数组从小到大不降序

      (其中 Ai 为翻转前的字符串大小 ,  Bi 为翻转后的字符串大小)

      考虑 dp[i][0] 表示前 i 个数已排好序,第 i 个选择 Ai 的代价

      dp[i][1] 表示前 i 个数已排好序,第 i 个选择 Bi 的代价

      那么在都合法的情况下 dp[i][0] = min(dp[i - 1][0] , dp[i - 1][1])

      dp[i][1] = min(dp[i  - 1][0] + c[i] , dp[i - 1][1] + c[i])

      不都合法的情况下删去几个转移即可

      最后答案为 min ( dp[n][0] , dp[n][1] )

    #include<bits/stdc++.h>
    #define rep(i,a,n) for (int i=a;i<=n;i++)
    #define int long long
    using namespace std;
    const int INF (0x3f3f3f3f3f3f3f3fll);
    const int N = 3e5 + 10;
    int c[N] , dp[N][2];
    string s[N] , t[N];
    signed main()
    {
        rep(i , 0 , N - 1) dp[i][0] = dp[i][1] = INF;
        int n ;
        cin >> n;
        rep(i , 1 , n) cin >> c[i];
        rep(i , 1 , n) cin >> t[i] , s[i] = t[i] , reverse(t[i].begin() , t[i].end());
        dp[1][0] = 0 , dp[1][1] = c[1];
        rep(i , 2 , n) 
        {
            if(s[i] >= s[i - 1]) dp[i][0] = dp[i - 1][0];
            if(s[i] >= t[i - 1]) dp[i][0] = min(dp[i][0] , dp[i - 1][1]);
            if(t[i] >= s[i - 1]) dp[i][1] = dp[i - 1][0] + c[i];
            if(t[i] >= t[i - 1]) dp[i][1] = min(dp[i][1] , dp[i - 1][1] + c[i]); 
        }
        int ans = min(dp[n][0] , dp[n][1]);
        if(ans == INF) cout << -1 << '
    ';
        else cout << ans << '
    ';
        return 0;
    }

    1800 - H. Bots

    题目链接:https://codeforces.com/contest/575/problem/H

    题意:

      你起初处于坐标系的 (0 , 0) 位置。现给你一个 N

      表示你可以活动的范围为 (0 , 0) 到 (N , N) 所形成的矩形之内

      每步你可以选择向上或者向右走即 (x , y) → (x + 1 , y) 或 (x , y + 1)

      问你到达矩形内的所有点的所有方案总和为多少

    分析:

      我们定义 dp[i][j] 表示从 (0 , 0) 到 (i , j) 的方案数

      则 $ans=sum ^{n}_{i=0}sum ^{n}_{j=0}dpleft[ i ight] left[ j ight] $

      因为从 (0 , 0) → (i , j) 一共要走 i + j 步,而其中有 i 步向上 , j 步向右

      所以一共有 $C^{i}_{i+j}$ 步 ,  即 dp[i][j] = $C^{i}_{i+j}$

      于是 $ans=sum ^{n}_{i=0}sum ^{n}_{j=0}C^{i}_{i+j}$

      又因为 $C^{b}_{a}+C^{b+1}_{a}=C^{b+1}_{a+1}$ , 所以式子可以化简为 $C^{n+1}_{2n+2}-1$

      (手写 latex 太累了,偷个懒 ( ´・∀・`))

      注意模数太大不能用lucas等 , 所以还是乖乖的算阶层吧

    #include<bits/stdc++.h>
    #define rep(i,a,n) for (int i=a;i<=n;i++)
    #define per(i,n,a) for (int i=n;i>=a;i--)
    #define int long long
    using namespace std;
    const int N = 3e5 + 10 , MOD = 1e9 + 7;
    int pow_mod(int x , int n , int mod)
    {
        int res = 1;
        while(n)
        {
            if(n & 1) res = res * x % mod;
            x = x * x % mod , n >>= 1;
        }
        return res;
    }
    int dp[N][2];
    signed main()
    {
        int n , res = 1;
        cin >> n;
        per(i , 2 * n + 2 , 2 * n + 2 - n) res *= i , res %= MOD;
        rep(i , 2 , n + 1) res *= pow_mod(i , MOD - 2 , MOD) , res %= MOD;
        cout << (res - 1 + MOD) % MOD << '
    ';
        return 0;
    }

    2000 - C. Industrial Nim

    题目链接:https://codeforces.com/contest/15/problem/C

    题意:

      现在有 N 个矿场 , 第 i 个矿场有 Mi 辆货车 

      每辆货车上的物品个数依次为 Xi , Xi + 1 ... Xi + M - 1

      现有两人轮流取物

      每次可以选择从任意矿场的任意一辆车取上 (1 ~ 该车的物品总量 ) 件物品

      当一方无法再取物时游戏结束,问先手赢还是后手赢

    分析:

      很显然这就是道赤裸裸的 NIM 博弈题 , 不懂为什么有会2000分?

      如果你不了解 NIM 博弈,推荐学习博客 博弈论

      于是按照 NIM 博弈的结论我们只要判断所有车的异或总和是否为0就可以了

      问题是 M 的范围很大,暴力异或肯定分分钟 Tle,那怎么办呢?

      其实也很简单 , 我们会发现一个矿场的货车物品数是以 1 为公差递增的

      而如果一个偶数 EV ^ (EV + 1) , 很显然结果为 1

      所以我们只要对 Xi 和 Mi 的奇偶性进行讨论就可以了

      具体操作还是看代码吧 (请原谅我喜欢偷懒(′ε`")

    #include<bits/stdc++.h>
    #define rep(i,a,n) for (int i=a;i<=n;i++)
    #define int long long
    using namespace std;
    signed main()
    {
        int n , m , x , ans = 0;
        cin >> n;
        rep(i , 1 , n)
        {
            cin >> x >> m;
            if(x & 1) 
            {
                ans ^= x;
                if((m - 1) & 1) ans ^= x + m - 1;
                int len = m - 1 >> 1;
                if(len & 1) ans ^= 1;
            }
            else 
            {
                if(m & 1) ans ^= x + m - 1;
                int len = m >> 1;
                if(len & 1) ans ^= 1;
            }
        }
        if(ans) cout << "tolik
    ";
        else cout << "bolik
    ";
        return 0;
    }
    凡所不能将我击倒的,都将使我更加强大
  • 相关阅读:
    职业的选择
    事务的隔离性理解
    浅谈CSS和JQuery实现鼠标悬浮图片放大效果
    jvm 类加载器
    jvm 类加载
    Spring 启动 Bean加载流程
    优雅的博客园客户端发布Forms版啦。
    Xamarin Forms中WebView的自适应高度
    2017回顾与2018目标
    优雅的博客园Android客户端
  • 原文地址:https://www.cnblogs.com/StarRoadTang/p/12618844.html
Copyright © 2020-2023  润新知