hihocoder[Offer收割]编程练习赛49 题解

1700 相似颜色
模拟 + 暴力,随便搞一搞就好了

#define others
#ifdef others
#include <iostream>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <string>
#include <map>
#include <set>
#endif // poj
#ifdef others
#include <bits/stdc++.h>
#endif // others
//#define file
//#define time
#define all(x) x.begin(), x.end()
using namespace std;
const double eps = 1e-8;
const double pi = acos(-1.0);
int dcmp(double x) {
    if(fabs(x)<=eps) return 0;
    return (x>0)?1:-1;
};
typedef long long LL;
typedef unsigned long long ULL;
void umax(int &a, int b) {
    a = max(a, b);
}
void umin(int &a, int b) {
    a = min(a, b);
}

void file() {
    freopen("pe.in", "r", stdin);
//    freopen("1.txt", "w", stdout);
}
/*
dp[i] = sigma(C(i, i-j)/(2^i) * (1 + dp[j]));
*/
namespace Solver {
    string str;
    LL cov1(char c) {
        if(isalpha(c)) return c - 'a' + 10;
        else return c - '0';
    }
    char cov2(LL c) {
        if(c <= 9) return '0' + c;
        else return c-10+'a';
    }
    struct A {
        LL ans;
        LL a, b, c;
    };
    LL cal(string s, string t) {
        LL sum = 0;
        for(int i = 1; i < 6; i+=2) {
            sum += (cov1(s[0+i])*16+cov1(s[i+1]) - (cov1(t[i+0])*16+cov1(t[i+1])))*(cov1(s[0+i])*16+cov1(s[i+1]) - (cov1(t[i+0])*16+cov1(t[i+1])));
        }
        return sum;
    }
    void solve() {
        cin >> str;
        A ans = {1e18, 0, 0, 0};
        for(LL i = 0; i <= 16; i++)
            for(LL j = 0; j <= 16; j++)
                for(LL k = 0; k <= 16; k++) {
                    string tmp = "#";
                    tmp += cov2(i);
                    tmp += cov2(i);
                    tmp += cov2(j);
                    tmp += cov2(j);
                    tmp += cov2(k);
                    tmp += cov2(k);
                    if(cal(str, tmp) < ans.ans) {
                        ans.ans = cal(str, tmp);
//                        cout<<i<<" "<<j<<" "<<k<<endl;
                        ans.a = i, ans.b = j, ans.c = k;
                    }
                }

        putchar('#');
        printf("%c%c%c", cov2(ans.a), cov2(ans.b), cov2(ans.c));
    }
}
int main() {
//    file();
    Solver::solve();
    #ifdef time
    printf("Time = %.5f ms", (double)clock()/CLOCKS_PER_SEC);
    #endif // time
    return 0;
}

1701 挑选子集
简单的计数问题。
首先从N个数挑出M个数,每个数两两的差都为K的倍数,等价于这些数模K同余。
因此按模K的余数进行分组,随后每组单独计数即可。

#define others
#ifdef others
#include <iostream>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <string>
#include <map>
#include <set>
#endif // poj
#ifdef others
#include <bits/stdc++.h>
#endif // others
//#define file
//#define time
#define all(x) x.begin(), x.end()
using namespace std;
const double eps = 1e-8;
const double pi = acos(-1.0);
int dcmp(double x) {
    if(fabs(x)<=eps) return 0;
    return (x>0)?1:-1;
};
typedef long long LL;
typedef unsigned long long ULL;
void umax(int &a, int b) {
    a = max(a, b);
}
void umin(int &a, int b) {
    a = min(a, b);
}

void file() {
    freopen("pe.in", "r", stdin);
//    freopen("1.txt", "w", stdout);
}
/*
dp[i] = sigma(C(i, i-j)/(2^i) * (1 + dp[j]));
*/
namespace Solver {
    int n, m, k;
    int v[111];
    LL C[111][111];
    const LL mod = 1000000009;
    void solve() {
        C[0][0] = C[1][0] = C[1][1] = 1;
        for(int i = 2; i < 111; i++) {
            C[i][0] = C[i][i] = 1;
            for(int j = 1; j < i; j++)
                C[i][j] = C[i-1][j-1] + C[i-1][j] % mod;
        }
        scanf("%d%d%d", &n, &m, &k);
        for(int i = 1; i <= n; i++) {
            int val;
            scanf("%d", &val);
            v[val%k]++;
        }
        LL res = 0;
        for(int i = 0; i <= k; i++) {
            if(v[i] >= m)
            res += C[v[i]][m];
            res %= mod;
        }
        cout<<res;
    };
}
int main() {
//    file();
    Solver::solve();
    #ifdef time
    printf("Time = %.5f ms", (double)clock()/CLOCKS_PER_SEC);
    #endif // time
    return 0;
}

1702 矩阵迷宫
走方格最小化问题,加两维分别表示当前的方向和已经转向的次数,然后正常DP即可。

#define others
#ifdef others
#include <iostream>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <string>
#include <map>
#include <set>
#endif // poj
#ifdef others
#include <bits/stdc++.h>
#endif // others
//#define file
//#define time
#define all(x) x.begin(), x.end()
using namespace std;
const double eps = 1e-8;
const double pi = acos(-1.0);
int dcmp(double x) {
    if(fabs(x)<=eps) return 0;
    return (x>0)?1:-1;
};
typedef long long LL;
typedef unsigned long long ULL;
void umax(LL &a, LL b) {
    a = max(a, b);
}
void umin(LL &a, LL b) {
    a = min(a, b);
}

void file() {
    freopen("pe.in", "r", stdin);
//    freopen("1.txt", "w", stdout);
}
/*
dp[i] = sigma(C(i, i-j)/(2^i) * (1 + dp[j]));
*/
namespace Solver {
    LL n;
    LL v[111][111];
    LL dp[111][111][2][30];
    LL cost[33];
    void solve() {
        for(LL i = 0; i <= 30; i++) cost[i] = 1LL<<(i-1);
        scanf("%lld", &n);
        for(LL i = 0; i < 111; i++)
            for(LL j = 0; j < 111; j++)
                for(LL k = 0; k < 30; k++)
                    dp[i][j][0][k] = dp[i][j][1][k] = 1e18;
        for(LL i = 1; i <= n; i++)
            for(LL j = 1; j <= n; j++)
                scanf("%lld", &v[i][j]);
        for(int i = 0; i < 2; i++)
            for(int j = 0; j < 30; j++)
                dp[1][1][i][j] = v[1][1];
        for(LL i = 1; i <= n; i++) {
            for(LL j = 1; j <= n; j++) {
                if(i == j && i == 1) continue;
                for(LL k = 0; k <= 1; k++) {
                    for(LL p = 0; p < 30; p++) {
                        if(i >= 2 && k == 0) {
                            umin(dp[i][j][k][p], dp[i-1][j][k][p] + v[i][j]);
                        } else if(j >= 2 && k == 1) {
                            umin(dp[i][j][k][p], dp[i][j-1][k][p] + v[i][j]);
                        }
                        if(p != 0 && k == 1 && j >= 2) {
                            umin(dp[i][j][k][p], dp[i][j-1][0][p-1] + v[i][j] + cost[p]);
                        } else if(p != 0 && k == 0 && i >= 2) {
                            umin(dp[i][j][k][p], dp[i-1][j][1][p-1] + v[i][j] + cost[p]);
                        }
                    }
                }
//                LL ans = 1e18;
//                for(LL k = 0; k < 30; k++)
//                    ans = min(ans, dp[i][j][0][k]), ans = min(ans, dp[i][j][1][k]);
//                cout<<ans<<" i = "<<i<<" j = "<<j<<endl;
            }
        }
        LL ans = 1e18;
        for(LL i = 0; i < 30; i++)
            ans = min(ans, dp[n][n][0][i]), ans = min(ans, dp[n][n][1][i]);
        cout<<ans;
    }
}
int main() {
//    file();
    Solver::solve();
    #ifdef time
    printf("Time = %.5f ms", (double)clock()/CLOCKS_PER_SEC);
    #endif // time
    return 0;
}

1703 比赛的时候不会,赛后看别人代码恍然大悟。
给出中序遍历,问字典序第 k 大的前序遍历是多少。
n最大 30 k 不超过二叉树的方案数。
二叉树的方案数就是括号序列的种类数,也就是卡特兰数,因此k longlong 范围内。
给出的是中序遍历,那么我们可以枚举根,然后在根的左边枚举左子树,根的右边枚举右子树。
假设当前根的左边有 x 个未确认点,右边有y个未确认点,那么显然存在的二叉树种类为 T[x]T[y] T[x] 是x个节点组成的二叉树的方案数,可以通过简单的DP得到。
因此我们可以先把所有数从小到大排序,枚举根,就可以逐渐缩小k,当确定了左右子树的时候,再递归下去解决即可,因为要求的是前序遍历,需要注意下统计答案的顺序。

#define others
#ifdef poj
#include <iostream>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <string>
#include <map>
#include <set>
#endif // poj
#ifdef others
#include <bits/stdc++.h>
#endif // others
//#define file
#define all(x) x.begin(), x.end()
using namespace std;
const double pi = acos(-1.0);

typedef long long LL;
typedef unsigned long long ULL;
void umax(int &a, int b) {
    a = max(a, b);
}
void umin(int &a, int b) {
    a = min(a, b);
}

void file() {
    freopen("a.in", "r", stdin);
//    freopen("1.txt", "w", stdout);
}

namespace Solver {
    LL n, k;
    const LL maxn = 33;
    LL T[maxn];
    LL v[maxn];
    vector<LL> G;
    void dfs(LL l, LL r, LL t) {
        if(l > r) return ;
        if(l == r) {
            G.push_back(v[l]);
            return ;
        }
        vector<pair<LL, LL>>vec;
        for(LL i = l; i <= r; i++) vec.push_back({v[i], i});
        sort(all(vec));
        for(LL i = 0; i < vec.size(); i++) {
            LL pos = vec[i].second;
            LL tmp = T[pos - l] * T[r - pos];
            if(tmp >= t) {
                G.push_back(v[pos]);
                dfs(l, pos-1, (t-1)/T[r-pos]+1);
                dfs(pos+1, r, (t-1)%T[r-pos]+1);
                break;
            } else t -= tmp;
        }
    }
    void solve() {
        T[0] = T[1] = 1;
        for(LL i = 2; i < maxn; i++) {
            for(LL j = 0; j < i; j++)
                T[i] += T[j] * T[i-j-1];
        }
        scanf("%lld%lld", &n, &k);
        for(LL i = 1; i <= n; i++) scanf("%lld", &v[i]);
        dfs(1, n, k);
        for(auto v:G) printf("%lld\n", v);
    }
};

int main() {
//    file();
    Solver::solve();
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值