AcWing第93场周赛

整除数

给定两个整数 $ n,k $,请你找到大于 $ n $ 且能被 $ k $ 整除的最小整数 $ x $。

输入格式

共一行,包含两个整数 $ n,k $。

输出格式

输出大于 $ n $ 且能被 $ k $ 整除的最小整数 $ x $。

数据范围

前 $ 4 $ 个测试点满足 $ 1 \le n,k \le 100 $。
所有测试点满足 $ 1 \le n,k \le 10^9 $。

输入样例1:

5 3

输出样例1:

6

输入样例2:

25 13

输出样例2:

26

输入样例3:

26 13

输出样例3:

39

题目分析

对于任意的\(n\)\(k\),都有\(n=q*k+r\),其中q是商,r是余数。$ 0 \le r < k$ 。
因此,分两种情况讨论即可。

  1. \(r=0\)。则此时余数为0,代表n被k整除。\(x=(q+1)*k\)
  2. \(r \le 0\)。则此时n不能被k整除,余数\(r\)一定严格小于k,则此时\(x=(q+1)*k\)

综上,\(x=(n/k+1)*k\)


#include <bits/stdc++.h>
using namespace std;
int n,k;
int main()
{
    cin>>n>>k;
    cout<<(n/k+1)*k<<endl;
    return 0;
}

数字替换

给定两个整数 n,x。

你可以对 x 进行任意次以下操作:

  • 选择 x 的一位数字 y,将 x 替换为 x×y。

请你计算通过使用上述操作,将 x 变为一个 n 位数字(不含前导 0),所需要的最少操作次数。

例如,当 n=3,x=2 时,对 2 进行如下 4 次操作,即可使其变为 3 位数字:

  1. 将 2 替换为 2×2=4。
  2. 将 4 替换为 4×4=16。
  3. 将 16 替换为 16×6=96。
  4. 将 96 替换为 96×9=864。

输入格式

共一行,包含两个整数 n,x。

输出格式

一个整数,表示将 x 变为一个 n 位数字,所需要的最少操作次数。

如果无解,则输出 -1

数据范围

所有测试点满足 2≤n≤19,1≤x<10n−1。

输入样例1:

2 1

输出样例1:

-1

输入样例2:

3 2

输出样例2:

4

输入样例3:

13 42

输出样例3:

12

题目分析

题目类似《小猫爬山》,要再去复习一下提高课的dfs和搜索剪枝了

  1. 倒序搜索 搜索顺序优化,快速得到一个解,而不是快速得到最优解

  2. 之前的方案比现在的这种方案小,则可以现在直接退出。

  3. 预判一下:如果之前的方案是k步,当前这种方案已经用了x步,发现离目的还需要n-x步
    即若当前的步数+相差的位数>=最优解,则可以直接退出了。

/*
题目类似《小猫爬山》,要再去复习一下提高课的dfs和搜索剪枝了
 1. 倒序搜索    搜索顺序优化,快速得到一个解,而不是快速得到最优解
 2. 之前的方案比现在的这种方案小,则可以现在直接退出。
 3. 预判一下:如果之前的方案是k步,当前这种方案已经用了x步,发现离目的还需要n-x步
 即若当前的步数+相差的位数>=最优解,则可以直接退出了。
*/

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

int ans = 0x3f3f3f3f;
int n;
void dfs(ll x,int res)
{
    int cnt = 0;  // 记录当前x的位数
    bool st[10]={0}; // 表示当前x要变化下一步的话,能用哪些数字
    for (ll i=x;i;i/=10)  // 求解x的位数和对于x来说哪些数字能用
    {
        cnt++;
        st[i%10]=true;
    }
    
    // 剪枝1:预判一下这种方案还有没有希望是答案
    if (res+n-cnt>=ans) return;
    
    
    if (cnt==n)
    {
        // 剪枝2:最优性剪枝
        if (res<ans)
            ans=res;
        return;
    }
    
    // 扩展求解答案,即从9~2每一个符合条件的数字都试
    for (int i=9;i>=2;i--)
    {
        if (st[i])
            dfs(x*i,res+1);
    }
    
}
int main()
{
    ll x;
    cin>>n>>x;
    dfs(x,0);
    
    if (ans==0x3f3f3f3f) ans=-1;
    cout<<ans<<endl;
    return 0;
    
}




异或值

给定一个长度为 $ n $ 的整数序列 $ a_1,a_2,…,a_n $。

请你找到一个非负整数 $ X $,使得 $ \max \limits_{1 \le i \le n} { a_i \oplus X } $ 的值尽可能小,其中 $ \oplus $ 表示按位异或。

输出 $ \max \limits_{1 \le i \le n} { a_i \oplus X } $ 的最小可能值。

输入格式

第一行包含整数 $ n $。

第二行包含 $ n $ 个整数 $ a_1,a_2,…,a_n $。

输出格式

一个整数,表示 $ \max \limits_{1 \le i \le n} { a_i \oplus X } $ 的最小可能值。

数据范围

前 $ 3 $ 个测试点满足 $ 1 \le n \le 3 $。
所有测试点满足 $ 1 \le n \le 10^5 \(,\) 0 \le a_i \le 2^{30}-1 $。

输入样例1:

3
1 2 3

输出样例1:

2

输入样例2:

2
1 5

输出样例2:

4

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 3000010, INF = 2e9;

int n;
int tr[N][2], idx;

void insert(int x)
{
    int p = 0;
    for (int i = 29; i >= 0; i -- )
    {
        int u = x >> i & 1;
        if (!tr[p][u]) tr[p][u] = ++ idx;
        p = tr[p][u];
    }
}

int dfs(int u, int d)
{
    if (d == -1) return 0;
    int f[2];
    for (int i = 0; i < 2; i ++ )
    {
        int p = tr[u][i];
        if (p) f[i] = dfs(p, d - 1);
        else f[i] = -1;
    }

    int res = INF;
    for (int i = 0; i < 2; i ++ )
    {
        int t = 0;
        for (int j = 0; j < 2; j ++ )
            if (f[j] != -1)
                t = max(t, f[j] + ((i ^ j) << d));
        res = min(res, t);
    }

    return res;
}

int main()
{
    scanf("%d", &n);
    while (n -- )
    {
        int x;
        scanf("%d", &x);
        insert(x);
    }

    printf("%d\n", dfs(0, 29));
    return 0;
}

posted @ 2023-03-08 00:24  勇敢龙龙  阅读(22)  评论(0)    收藏  举报