寒假每日一题(入门组)Week2

756. 蛇形矩阵 (1月11日)

分析

定义方向上右下左, 然后res里放元素即可

联动leetcode54

code

#include <iostream>
#include <vector>
using namespace std;
const int N = 110
int n, m;

int main(){
    scanf("%d%d", &n, &m);
    int d = 1;
    int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
    int x = 0, y = 0;
    vector<vector<int>> res(n, vector<int>(m));
    for (int i = 1; i <= n * m; i ++ ){
        res[x][y] = i;
        int a = x + dx[d], b = y + dy[d];
        if (a < 0 || a >= n || b < 0 || b >= m || res[a][b]){
            d = (d + 1) % 4;
            a = x + dx[d], b = y + dy[d];
        }
        x = a, y = b;
    }
    for (int i = 0; i < n; i ++ ){
        for (int j = 0; j < m; j ++ )
            cout << res[i][j] << ' ';
        cout << endl;
    }
    return 0;   
}

1113. 红与黑(1月12日)

分析

洪水灌溉模板题

code(bfs)

#include <iostream>
#include <queue>
using namespace std;
const int N = 30;
int n, m;
char g[N][N];
typedef pair<int, int> PII;
#define x first
#define y second

int bfs(int x, int y){
    int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
    queue<PII> q;
    q.push({x, y});
    int res = 1;
    while (q.size()){
        auto t = q.front(); q.pop();
        for (int i = 0; i < 4; i ++ ){
            int sx = t.x + dx[i], sy = t.y + dy[i];
            if (sx >= 0 && sx < n && sy >= 0 && sy < m && g[sx][sy] == '.'){
                q.push({sx, sy});
                g[sx][sy] = '#';
                res ++;
            }
        }
            
    }
    return res;
}

int main(){
    while (scanf("%d%d", &m, &n), n || m){
        for (int i = 0; i < n; i ++ ) scanf("%s", g[i]);
        
        int x, y;
        for (int i = 0; i < n; i ++ )
            for (int j = 0; j < m; j ++ )
                if (g[i][j] == '@') x = i, y = j;
        cout << bfs(x, y) << endl;
    }
    return 0;
    
}

code(dfs)

递归中res 记录由当前点出发可以扩展到哪些点, 然后返回给上一层
在这里插入图片描述

#include <iostream>
#include <queue>
using namespace std;
const int N = 30;
int n, m;
char g[N][N];
typedef pair<int, int> PII;
#define x first
#define y second

int dfs(int x ,int y){
    int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
    g[x][y] = '#';
    int res = 1;
    
    for (int i = 0; i < 4; i ++ ){
        int sx = x + dx[i], sy = y + dy[i];
        if (sx >= 0 && sx < n && sy >= 0 && sy < m && g[sx][sy] == '.') {
            res += dfs(sx, sy);
        }
    }
    return res;
}

int main(){
    while (scanf("%d%d", &m, &n), n || m){
        for (int i = 0; i < n; i ++ ) scanf("%s", g[i]);
        
        int x, y;
        for (int i = 0; i < n; i ++ )
            for (int j = 0; j < m; j ++ )
                if (g[i][j] == '@') x = i, y = j;
        cout << dfs(x, y) << endl;
        
    }
    return 0;
    
}

1346. 回文平方 (1月13日)

分析

枚举每一个数, 比如x, 先求下 ( x 2 ) b (x^2)_{b} (x2)b, 比如 y = ( x 2 ) b y = (x^2)_{b} y=(x2)b, 如果 y y y是回文数, 那么输出 ( x ) b , ( x 2 ) b (x)_b, (x^2)_b (x)b,(x2)b

进制转换

问题在于如何将 ( x ) 10 (x)_{10} (x)10转化为b进制的数 ---- 短除法
比如 ( 123 ) 10 (123)_{10} (123)10 转化为3进制
对123 不断除以3, 直到商为0位置, 右边是余数
那么转化为3进制后的数为倒着看余数
在这里插入图片描述
课堂练习
( 245 ) 10 = ( x ) 5 (245)_{10} = (x)_5 (245)10=(x)5
在这里插入图片描述
命题:短除法的正确性

证明:
在这里插入图片描述

判断回文

双指针算法, i前指针往后走, j后指针往前走, 每次比较下当前所指的数是否相同, 如果不同的话, 就不是回文数, 如果相同, 则继续往中间靠拢

扩展

  1. 10进制转化为其他进制 — 短除法
  2. 其他进制转化成10进制 ? 直接扫描一遍做

( 11101 ) 2 (11101)_2 (11101)2
= 1 ∗ 2 4 + 1 ∗ 2 3 + 1 ∗ 2 2 + 0 ∗ 2 1 + 1 ∗ 2 0 =1*2^4 + 1* 2^3 + 1* 2^2 + 0 * 2^1 + 1* 2^0 =124+123+122+021+120

但是写代码的时候, 一般不这么写, 因为你需要先算下 2 4 , 2 3 , 2 2 , 2 1 , 2 0 2^4, 2^3, 2^2, 2^1, 2^0 24,23,22,21,20, 算的次数比较多
秦九韶算法
比如算 a n x n + a n − 1 x n − 1 + . . . + a 0 x 0 a_nx^n + a_{n - 1}x^{n - 1} + ... + a_0x_0 anxn+an1xn1+...+a0x0
先算 a n a_n an, 第2次算 a n x + a n − 1 a_nx + a_{n - 1} anx+an1, 然后第3次算 ( a n x + a n − 1 ) ∗ x + a n − 2 (a_nx + a_{n - 1}) * x + a_{n - 2} (anx+an1)x+an2, 第4次 ( ( a n x + a n − 1 ) ∗ x + a n − 2 ) ∗ x + a n − 3 ((a_nx + a_{n - 1}) * x + a_{n - 2})* x + a_{n - 3} ((anx+an1)x+an2)x+an3, 依此类推, 做n + 1次, 就可以计算得到结果
发现只要做n次加法, n次乘法就可以了, 不需要预处理指数的问题
例子:
( 11101 ) 2 (11101)_2 (11101)2
计算第2位的时候: 1 ∗ 2 + 1 = 3 1 * 2 + 1 = 3 12+1=3
计算第3位的时候: 3 ∗ 2 + 1 = 7 3 * 2 + 1 = 7 32+1=7
计算第4位的时候: 7 ∗ 2 + 0 = 14 7 * 2 + 0 = 14 72+0=14
计算第5位的时候: 14 ∗ 2 + 1 = 29 14 * 2 + 1 = 29 142+1=29
代码:
在这里插入图片描述
3. 如何将其他进制转化为其他进制(a进制转化为b进制)
最简单的做法 a —> 10 —> b
也可以直接用短除法做

联动题

acwing 124.进制转换

code

#include <iostream>
#include <algorithm>
using namespace std;

char get(int x){ // 如果高于10进制, 转化成A
    if (x <= 9) return x + '0';
    return x - 10 + 'A';
}

string base(int n, int b){ // 短除法
    string num;
    while (n) num += get(n % b), n /= b;
    reverse(num.begin(), num.end());
    return num;
}

bool check(string num){
    for (int i = 0, j = num.size() - 1; i < j; i ++, j -- )
        if (num[i] != num[j]) return false;
    return true;
}
int main(){
    int b;
    cin >> b;
    for (int i = 1; i <= 300; i ++ ){
        auto num = base(i * i, b); // i * i 的 b 进制表示
        if (check(num)){
            cout << base(i, b) << ' ' << num << endl;
        }
    }
    return 0;
}

680. 剪绳子(1月14日)

分析

转换下思想, 如果告诉我们已经切出来x长度, 然后问n根绳子一共可以切出多少条长度为x的, 那就比较容易了

比方说第1条绳子可以裁出1条长度为x的绳子, 第2条绳子可以裁出2条长度为x的绳子, 第3条绳子可以裁出1条长度为x的绳子, 总共可以裁出4条长度为x的绳子, 所以长度为x的绳子, 我们最多可以裁出4条
在这里插入图片描述
所以发现直接求最优解不好求, 但是已知x, 让我们求可以裁出多少根的话, 就比较容易了
考虑能不能用二分, 可以帮助我们将 最优化问题->判定问题
判定问题比原来的问题多了一个额外的条件x

求当前绳子能够裁剪出多少条长度为x的绳子: ⌊ L i x ⌋ \lfloor \frac{L_i}{x} \rfloor xLi , 然后遍历下每根绳子, 求和
二分之前, 先考虑下能不能二分(即判断mid无论何种情况, 能否将区间缩小一半)
假如二分中点mid成立, 那么答案区间在[mid, R]
mid不成立, 说明答案一定不在右边, 因为mid⬆️ ∑ ⌊ L i m i d ⌋ \sum \lfloor \frac{Li}{mid} \rfloor midLi, 会更得更小, 因此答案所在区间变成[L, mid]
因此, 不管怎样, 答案所在的区间长度都会/2, 不断/2, 区间长度变得很小, 直到小于eps

code

#include <iostream>
using namespace std;
const int N = 100010;

int n, m;
int w[N];

bool check(double x){
    int cnt = 0;
    for (int i = 0; i < n; i ++ )
        cnt += w[i] / x;
    return cnt >= m;
}

int main(){
    cin >> n >> m;
    for (int i = 0; i < n; i ++ ) cin >> w[i];
    
    double l = 0, r = 1e9;
    while (r - l > 1e-4){
        double mid = (l + r) / 2;
        if (check(mid)) l = mid;
        else r = mid;
    }
    
    printf("%.2lf\n", l);
    return 0;
}

1227. 分巧克力(1月15日)

分析

二分长度即可

code

#include <iostream>
using namespace std;
const int N = 1e5 + 10;
int a[N], b[N];
int n, k;

bool check(int x){
    int res = 0;
    for (int i = 0; i < n; i ++ ){
        res += (a[i] / x) * (b[i] / x);
    }
    
    return res >= k;
}

int main(){
    scanf("%d%d", &n, &k);
    for (int i = 0; i < n; i ++ ){
        scanf("%d%d", &a[i], &b[i]);
    }
    
    int l = 1, r = N;
    while (l < r){
        int mid = l + r  + 1 >> 1;
        if (check(mid)) l = mid;
        else r = mid - 1;
    }
    
    printf("%d\n", l);
    return 0;
}

422. 校门外的树(1月16日)

分析

题目给了总区间 求除去给定另外一段区间后, 剩余的点的数量
直接扫描一遍给的区间, 标记下, 然后再扫描一遍总区间, 对没打标记的点统计下个数, 就可以了

code

#include <iostream>
using namespace std;
const int N = 100010;
bool st[N];
int res;
int l, m;

int main(){
    cin >> l >> m;
    while (m -- ){
        int a, b;
        scanf("%d%d", &a, &b);
        for (int i = a; i <= b; i ++ ) st[i] = 1;
    }
    
    for (int i = 0; i <= l; i ++ ) res += !st[i];
    
    cout << res << endl;
    return 0;
}

429. 奖学金(1月17日)

分析

注意排序的写法
错误写法(要重视)

struct Stu{
    int a, b, c, sum, id;
    bool operator < (Stu &W){
        return sum > W.sum;
        if (sum == W.sum) return a > W.a;
        if (a == W.a) return id < W.id;
    }
}stu[N];

这样写sum == W.sum的时候会在第1个语句sum > W.sum返回0, 无法继续判断

code

#include <iostream>
#include <algorithm>
using namespace std;
const int N = 310;
struct Person{
    int id, sum, a, b, c;
    bool operator < (const Person &w){
        if (sum != w.sum) return sum > w.sum;
        if (a != w.a) return a > w.a;
        return id < w.id;
    }
}p[N];
int n;
int main(){
    cin >> n;
    for (int i = 1; i <= n; i ++) {
        int a, b, c;
        cin >> a >> b >> c;
        p[i] = {i, a + b + c, a, b, c};
    }
    sort(p + 1,  p + n + 1);
    for (int i = 1; i <= 5; i ++) cout << p[i].id << ' ' << p[i].sum << endl;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值