2024.07.03 题目整理

B:羊腿复制器

时间限制: 1.000 Sec  内存限制: 256 MB
提交状态

题目描述

唐克老师有一个用于存放羊腿的神奇装置,这个装置呈一个桶的形状,深度无限大,其中每一层都可以存放一个羊腿
每次唐克老师往桶里放入羊腿时,只能放在最顶层羊腿的更上一层,而每次取出羊腿时也只能取出最顶层的羊腿
例如唐克老师的桶里依次存放了 3 个羊腿,质量分别为 1,2,3,那么此时唐克老师只能取出最顶层质量为 3 的羊腿,不能跨过 3 直接取质量为 2 和 1 的羊腿
现在唐克老师给这个装置加了三个更加神奇的功能——生成、合成与复制!
1. 生成功能:唐克老师可以凭空生成一个质量为 1 的羊腿,并将它放在装置最顶层
2. 合成功能:唐克老师可以将现在处于最顶层的两个羊腿合并成一个羊腿,并且羊腿质量不会发生消耗,并将合成后的羊腿放在装置最顶层
3. 复制功能:唐克老师可以将现在处于最顶层的羊腿完美复制一份,并将它放在装置最顶层
例如唐克老师可以依次使用如下按钮:`生成、生成、合成、复制、生成、合成、合成`
这样的操作可以凭空得到一个质量为 5 的羊腿
假设三种功能的能量消耗均一样,现在唐克老师想知道最少需要使用多少次功能,可以凭空得到一个质量为 n 的羊腿?
并且唐克老师不想浪费粮食,他不希望最终装置中还存在其他羊腿

输入

输入第一行包含一个整数 , 表示询问次数
每行包含一个正整数 ,表示唐克老师想要得到的羊腿质量


输出

对于每一次询问,输出唐克老师最少需要使用功能的次数

样例输入 Copy

1
5

样例输出 Copy

7

提示

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 1e5 + 10;
ll t, n, stk[N], ans[N], mn, sum, idx;
void dfs(ll step)
{
    /* 剪枝 */
    if (sum == n)
    {
        mn = min(mn, step + idx - 1);
        /*
            当前已经执行step步,剩余的idx个元素
            需要用idx-1步来进行合并,
            故总步数为step + idx - 1;
        */
        return;
    }
    if (step + idx - 1 >= mn or sum > n)
    {
        /*
            当前步数已经不可能是最小值
                or
            羊腿已经浪费
        */
        return;
    }
    if (idx >= 2) // 合并
    {
        int temp = stk[idx];
        stk[--idx] += temp;
        dfs(step+1);
        stk[idx] -= temp;
        stk[++idx] = temp;
    }
    if (idx >= 1) // 复制
    {
        stk[idx + 1] = stk[idx];
        idx++;
        sum += stk[idx];
        dfs(step + 1);
        sum -= stk[idx];
        idx--;
    }
    // 生成
    stk[++idx] = 1;
    sum++;
    dfs(step + 1);
    sum--;
    idx--;

}
void init()
{
    for (int i = 1;i <= 100; i++)
    {
        mn = 1e9+7;
        n=i;
        idx=0;
        dfs(0);
        ans[i]=mn;
    }
}
int main()
{
    init();
    cin >> t;
    while (t--)
    {
        scanf("%d", &n);
        printf("%d\n", ans[n]);
    }
    return 0;
}

A: 羊腿分配

时间限制: 1.000 Sec  内存限制: 256 MB
提交 状态

题目描述

众所周知,唐克老师家里存着非常多的羊腿,一共有 m 只,依次编号为 1~ m,每只羊腿都有自己的大小 bi
当然,作为强迫症的唐克老师已经将这 m 只羊腿从小到大排好了。
现在唐克老师准备请群里一共 n 个小伙伴吃羊腿。
为了不浪费粮食,唐克老师统计了每个小伙伴的食量 ai,表示第 i 个小伙伴最多只能吃下编号为 ai 的羊腿
当然,为了公平,每个小伙伴只能分到一个羊腿。
如果某个小伙伴 x 没有办法分到适合他吃的羊腿,那么唐克老师会为他准备好质量为 bax 的牛肉来补偿他
现在唐克老师想知道,他最少需要准备多少质量的牛肉?

输入

输入第一行包含两个正整数 n,m,表示有 n 个小伙伴和 m 个羊腿
第二行包含 n 个整数 ai,分别表示每个小伙伴的食量
第三行包含 m 个整数 bi,分别表示每个羊腿的大小

对于 20% 的数据: n,m≤10
对于 60% 的数据: n,m,ai≤10000
对于 100% 的数据:n,m≤100000, 1≤bi≤109,1≤ai≤m

输出

输出唐克老师最少需要准备的牛肉质量

样例输入 Copy

5 4
2 3 4 3 2
3 9 20 100

样例输出 Copy

9

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
using ll = long long;
ll a[N], b[N], res;
int main()
{
    int n, m;
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
        scanf("%lld", &a[i]);
    for (int i = 1; i <= m; i++)
        scanf("%lld", &b[i]);
    sort(a + 1, a + n + 1);
    ll lftidx = a[n];
    for (int i = n; i >= 1; i--)
    {
        if (lftidx > 0)
        // 还有羊腿
        {
            if (a[i] >= lftidx) // 还能吃
            {
                lftidx--;
            }
            else // 吃不下了
            {
                lftidx = a[i];
                // 跳到能吃得下的地方
                lftidx--;
            }
        }
        else
        // 没有羊腿了
        {
            res += b[a[i]];
            // 补偿牛腿数
        }
 
    }
    cout << res << endl;
    return 0;
}

C: 装备强化

时间限制: 1.000 Sec  内存限制: 256 MB
提交 状态

题目描述

众所周知,唐克很喜欢玩游戏,这天他玩的游戏中新出了一个强(ke)化(jin)系统,允许玩家在一件装备上镶嵌强化石
而常规的概率强化已经无法吸引玩家了,所以新推出的这个强化系统的强化方式是这样的
每件装备拥有一个独立的强化界面,这个强化界面可以看作一个 n * m 的矩阵,每个点都可以镶嵌一颗强化石
在镶嵌了强化石后,装备的强化系数就是强化石构成的等腰三角形个数
这里的等腰三角形是指(镶嵌界面中 `.` 表示为空, `*` 表示镶嵌了强化石)
大小为 1 的三角形
```
*
```
大小为 2 的三角形
```
.*.
***
```
大小为 3 的三角形
```
..*..
.***.
*****
```
依次类推...
比如一件装备拥有一个 3 * 5 的强化界面
```
..*..
.****
*****
```
上述装备镶嵌了 10 颗强化石,获得的强化系数是 15
现在唐克已经给自己的装备镶嵌好了强化石,他想知道这件装备的强化系数是几?

输入

输入第一行包含两个正整数 n,m 表示这件装备的强化界面
接下来 n 行,每行一个长度为 m 的字符串,仅包含 `.` 和 `*`,其中 `.` 表示为空,`*` 表示这个格子镶嵌了强化石

输出

输出一个整数表示强化系数

样例输入 Copy

3 5
..*..
.****
*****

样例输出 Copy

15

提示

对于 30% 的数据: n,m ≤ 5
对于 60% 的数据: n,m ≤ 500
对于 100% 的数据:n,m ≤ 1000
#include <bits/stdc++.h>
using namespace std;
 
int main()
{
    int n, m;
    cin >> n >> m;
    vector<vector<int>> dp(n, vector<int>(m, 0));
    vector<string> matrix(n);
    for (int i = 0; i < n; ++i)
    {
        cin >> matrix[i];
    }
    for (int i = n - 1; i >= 0; --i)
    {
        for (int j = 0; j < m; ++j)
        {
            if (matrix[i][j] == '*')
            {
                dp[i][j] = 1;
                if (i < n - 1 && j > 0 && j < m - 1)
                {
                    dp[i][j] += min({dp[i + 1][j - 1], dp[i + 1][j], dp[i + 1][j + 1]});
                }
            }
        }
    }
 
    int ans = 0;
    for (int i = 0; i < n; ++i)
    {
        for (int j = 0; j < m; ++j)
        {
            ans += dp[i][j];
        }
    }
 
    cout << ans << '\n';
    return 0;
}

 

题目描述

唐克老师有一个长度为 n 的数组,但是这个数组发生了一些奇妙的变化——每一秒这个数组都在不断的收缩!
每一秒,相邻的两个数字会合并成一个,产生一个新的数组,一直搜索到数组只剩下两个数字
每一次的合并,就是将两个数字相加
例如有一个长度为 5 的数组 [1,2,3,4,5]
第一秒:会合并 (1,2),(3,4),因为没有第六个数字,所以 5 不变,即变成新数组 [3,7,5]
第二秒:会合并 (3,7),因为没有第四个数字,所以 5 不变,即变成新数组 [10,5]
此时,数组收缩到只有两个数字,结束变化
现在唐克老师想知道,这个数组最后两个数字的平方和会是多少?

输入

第一行给出两个正整数 n,k,n 表示数组长度,k 表示输入数据组数
接下来 k 行,每行包含两个整数 x,y 表示数组接下去有 x 个数字 y,具体请看样例解释

输出

输出最后两个数字的平方和,由于答案可能很大,请对 109 + 7 取模

样例输入 Copy

7 2
3 1
4 2

样例输出 Copy

61

提示

输入给出了 3 个 1 和 4 个 2,即数组为 [1,1,1,2,2,2,2],第一秒变为 [2,3,4,2],第二秒变为 [5,6],答案即为 52+62=61

对于 30% 的数据,满足 1 ≤ k ≤ n ≤ 103
对于 60% 的数据,满足 1 ≤ n ≤ 105
对于 80% 的数据,满足 1 ≤ n ≤ 1010
对于 100% 的数据,满足 1 ≤ n < 1018, 1 ≤ k ≤ 105, 1 ≤ x ≤ 106, 1 ≤ y ≤ 109。
特别的保证:对于所有数据满足Σx = n
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pll = pair<ll, ll>;
const int mod = 1e9 + 7;
ll n, k, ok;
vector<pll> data, ans;
vector<pll> process(vector<pll> data)
{
    vector<pll> temp; // 临时数组
    ll len = data.size(); // 数据中不同数的个数
    ll last_x = 0, last_y; // 临时变量, 上一个x, 上一个y
    ok = 0; // 用来做标记的, 表示还剩【几个数】
    for (int i = 0; i < len; i++)
    {
        if (last_x != 0)
        {
            // x有残留,上一个x是奇数,会剩下。
            data[i].first--;
            temp.emplace_back(make_pair(1, (last_y + data[i].second) % mod));
            ok++;
            last_x = last_y = 0;
        }
        ll x = data[i].first, y = data[i].second;
        if (x & 1)
        {
            // 奇数的特殊情况处理。
            last_x = 1;
            x--;
            last_y = y;
        }
        if (x > 0)
        {
            // 合并之后放回去。
            temp.emplace_back(make_pair(x / 2, y % mod * 2));
            ok += x / 2;
        }
    }
    if (last_x != 0)
    {
        temp.emplace_back(make_pair(1, last_y));
        ok++;
    }
    if (ok > 2)
    {
        // 还剩不止两个数,递归继续处理
        return process(temp);
    }
    else
    {
        // 可以了,返回
        return temp;
    }
}
int main()
{
    cin >> n >> k;
    for (int i = 1; i <= k; i++)
    {
        ll a, b;
        scanf("%lld%lld", &a, &b);
        data.emplace_back(make_pair(a, b));
    }
    ans = process(data);
    if (ans.size() == 1)
    {
        // 此时同样的数只剩一种
        ll x = ans[0].second;
        cout << ((x % mod) * (x % mod) + (x % mod) * (x % mod)) % mod;
    }
    else
    {
        // 还有两类数
        ll x = ans[0].second, y = ans[1].second;
        cout << ((x % mod) * (x % mod) + (y % mod) * (y % mod)) % mod;
    }
    return 0;
}

 

posted on 2024-07-03 23:24  CuberW  阅读(160)  评论(0)    收藏  举报