牛客网OJ题解--20210310

可编程拖拉机比赛

https://ac.nowcoder.com/acm/problem/14597

本系列记录翀翀😐痛苦的刷题日志,所有题目均来自于牛客网OJ题目,坚持刷题谈起来容易做起来难,希望我可以坚持下去,这里仍然分享一段励志文案:每个人都有梦想,然而有些人把梦想变成了现实,有些人的梦想依旧是梦想,只因为他们为梦想付出的努力程度不一样,他们坚持的时间不一样,最终才有这样的结果。

NC14597-可编程拖拉机比赛

题目链接

https://ac.nowcoder.com/acm/problem/14597

题目描述

“这个比赛,归根结底就是控制一个虚拟的小拖拉机跑完整个赛道。一般一场比赛会有 9 个到 13 个赛道,最后看能跑完多少个赛道。”通常在一场可编程拖拉机比赛中,分别会有实际参赛队伍数 10%、20%、30% 向下取整的队伍获得金、银、铜牌,其余队伍获得荣誉提名,俗称“铁牌”。但是主办方往往会多准备一些奖牌,那么在发奖牌的时候会按照比例向上取整发出的奖牌以减少浪费,就会有一些原本获得银牌的队伍获得了金牌。现在给出一个赛区的规模,也就是这个赛区的实际参赛队伍数,小 Q 同学想知道有多少队伍的奖牌会由银变金、由铜变银、由铁变铜。输入只有一行,包含一个整数 n (10 <= n <= 1000),表示实际参赛队伍数。输出一行,包含三个由空格分隔的整数,分别表示奖牌会由银变金、由铜变银、由铁变铜的队伍数。

测试样例

输入

115

输出

1 1 2

解题思路

我们首先要知道,当一个金牌人数增加时,那么根据堆积的效应,银牌和铜牌的人数也会加1,当银牌人数增加时,金牌人数不受影响,只是铜牌受影响,而铜牌人数改变不影响任何人数。当前10%不是刚好整数,即n%10不是0时,说明规矩改变后,金牌人数会加1,且最多只会有增多一个人,银牌就是前20%有问题,所以应该是模5不是0时,说明规矩改变后,银牌人数会加1且最多只会增加一个人,同理铜牌是n%(10/3)的时候,会增加一人。

解题代码

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

int main()
{
    int a = 0, b = 0, c = 0;
    int n;
    cin >> n;
    //当乘10%即模10的时候不是整数,那么所有牌的人数都++
    if (n % 10 != 0)
    {
        a++;
        b++;
        c++;
    }
    //当乘20%即模10/2=5的时候不是整数,那么银、铜人数都++
    if (2 * n % 10 != 0)
    {
        b++;
        c++;
    }
    //当乘30%即模10/3的时候不是整数,那么铜牌人数++
    if (3 * n % 10 != 0)
    {
        c++;
    }
    cout << a << " " << b << " " << c << endl;
    system("pause");
    return 0;
}

NC14599-子序列

题目链接

https://ac.nowcoder.com/acm/problem/14599

题目描述

定一个小写字母字符串T ,求有多少长度为m的小写字母字符串S满足,T是S的一个子序列(不需要连续)。第一行一个字符串T,第二行一个正整数m,输出答案对109+7取模的值。

测试样例

输入

a
2

输出

51

说明

长度为2的里面有a的串有51种

解题思路

逆元+组合数题,自己的没过,但是思路正确,直接看注释吧

解题代码

#include <bits/stdc++.h>
const int maxx = 1e5 + 15;
#define ll long long
//取模提前声明,好习惯
const ll mod = 1e9 + 7;
using namespace std;
string s;

//快速幂取模板子,注意第一个放C底下的数,第二个放C上面的数
ll qmi(int a, int k)
{
    a %= mod;
    //ans是结果值
    int ans = 1;
    //采用的是二进制的计算方法
    while (k)
    {
        //这里k在机器中是二进制表示,与1相与,只有k的最后一位是1才能使得if条件成立
        if (k & 1)
            //此时ans就乘以一个基数a
            ans = ans * a % mod;
        //每一次a都要扩大一倍表示下一位的位权
        a = a * a % mod;
        //k右移一位取最低位
        k >>= 1;
    }
    return ans;
}

//逆元取模的组合数板子
ll C(ll k, ll n)
{
    int num = 1;
    for (int i = 1, j = k; i <= n; i++, j--)
    //一共分子和分母只需要计算n次
    {
        //这里用来计算Ckn
        num = num * j % mod;
        //这里是求n!的逆元,以便能够取模
        num = num * qmi(i, mod - 2) % mod;
    }
    return num;
}

int main()
{
    ll i, m, n;
    cin >> s;
    cin >> m;
    n = s.length();
    //多余出来的位数
    ll ans = 0;
    //i至少有n个,同时还忽悠m-n个多于的位,这里就是在模拟这些位放在哪里
    //如果是插在子序列的左边或中间,那么就只能有25个选择
    //否则子序列右边就是26个选择
    //枚举子序列左边的位数(包括子序列自身)
    //那么i-n是插到子序列左边的多于位数的个数(有25个选择的位数个数)
    //m-i是放到子序列右边即后面的位数个数(有26个选择的位数的个数)
    //实际上模拟取模的二项式定理
    for (i = n; i <= m; i++)
    {
        //注意当长度为4,那么实际上C的底数是3即为n-1,上面就是
        ans += C(n - 1, i - 1) * qmi(25, i - n) % mod * qmi(26, m - i) % mod;
        ans %= mod;
    }
    cout << ans << endl;
    system("pause");
    return 0;
}
全部评论

相关推荐

06-04 09:27
门头沟学院 Java
点赞 评论 收藏
分享
06-19 19:06
门头沟学院 Java
码农索隆:别去东软,真学不到东西,真事
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务