Wannafly挑战赛13【A B C D】【逆元+数学+优先队列】

本文解析了四道算法竞赛题目,包括小号昵称变化计数、军训遮阳概率计算、好矩阵构造及计数、生日蛋糕分割问题。通过具体实例展示了如何使用数学技巧和数据结构解决问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

A zzy的小号

链接:https://www.nowcoder.com/acm/contest/80/A
来源:牛客网
题目描述
学家zzy根据字体的特点,创建了一系列小号… I_Love_Chtholly!
又到了打wannafly的时候,许许多多的大佬准备注册小号开始虐场,zzy也不例外,他发现他的电脑的字体有一个特点!某些不同的字符所显示的是一样的!
满足以下四种情况之一,所显示的字符是一样的
1、两个字符互为英文字母的大小写
2、大写的’i’和小写的’l’
3、大写的’o’和数字’0’
4、基于前三种情况,三个字符a,b,c,如果a和b显示相同,b和c显示相同,那么a和c显示也是相同的
珂学家zzy想知道,对于一个他看起来相同的昵称,有多少个看起来一样的昵称
两个字符串看起來一样当且仅当长度一样且每个对应的位置的字符看起來一样
输入描述:
一个字符串,只包含大小写字母和数字
输出描述:
共一行一个整数,表示看起来一样的昵称数,由于这个数比较大,所以只要求输出模1e9 + 7意义下的解
示例1
输入
abcdl
输出
64
说明
第一个位置、第二个位置、第三个位置、第四个人位置都只有两种显示相同的字符
第五个位置有四种显示相同的字符
备注:
字符串长度1<=|S|<=1e5

分析:注意读题和模拟,这是一道很容易卡人的题。。。

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

const int MAXN = 2e5 + 10;
const LL mod = 1e9 + 7;
char str[MAXN];

int main() {
    LL ans = 1;
    cin>>str;
    int len = strlen(str);
    for(int i = 0; i < len; ++i) {
        if(str[i] == 'i' || str[i] == 'L' || str[i] == 'I' || str[i] == 'l') ans *= 4;
        else if(str[i] == 'o' || str[i] == 'O' || str[i] == '0') ans *= 3;
        else if(str[i] >= 'a' && str[i] <= 'z' || str[i] >= 'A' && str[i] <= 'Z')ans *= 2;
        ans %= mod;
    }
    printf("%lld\n", ans % mod);
    return 0;
}

B Jxc军训

链接:https://www.nowcoder.com/acm/contest/80/B
来源:牛客网
题目描述
在文某路学车中学高一新生军训中,Jxc正站在太阳下站着军姿,对于这样的酷热的阳光,Jxc 表示非常不爽。
Jxc将天空看做一个n*n的矩阵,此时天上有m朵云,这些云会随机分布在m个不同的位置,同时太阳会随机出现在一个位置,Jxc想知道他被太阳晒到的概率是多少,由于他仍在站军姿,所以这个有趣的问题就交给了你。考虑到精度问题,Jxc只需要知道这个概率在对998244353取模意义下的值。
Tips:一个分数p/q在模意义下的值即p*q-1在模意义下的值,Xp-11 (mod p)
输入描述:
输入只有一行,包含两个整数n、m。n和m的意义见题面.
输出描述:
第一行包含一个整数Ans,为答案
示例1
输入
2 2
输出
499122177
备注:
1 <= n, m <= 2000,m <=n^2

公式: (n2m)/n2modp ( n 2 − m ) / n 2 m o d p ,费马小定理搞一下逆元就行;

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

const int MAXN = 2e5 + 10;
//const LL mod = 1e9 + 7;
const LL mod = 998244353;
char str[MAXN];

LL Q_mod(LL a, LL b) {
    LL ans = 1;
    while(b) {
        if(b & 1) ans = (ans * a) % mod;
        a = (a * a) % mod;
        b >>= 1;
    }
    return ans;
}

int main() {
    LL n, m;
    scanf("%lld %lld", &n, &m);
    printf("%lld\n", ((n * n - m) * Q_mod(n * n, mod - 2)) % mod);
    return 0;
}

C zzf的好矩阵

链接:https://www.nowcoder.com/acm/contest/80/C
来源:牛客网
题目描述
一个8 * 8的棋盘,第一个格子放1个麦穗,第二个格子放2个麦穗,第三个格子放4个麦穗……那么最后,共要放几个麦穗呢?
zzf表示这个问题实在太简单,于是重新规定了游戏的规则。
初始的棋盘为空,棋盘大小为p*p,然后他要对棋盘进行若干次操作,可以被选择的操作如下:
1、选择一行,每个格子再放一个麦穗
2、选择一列,每个格子再放一个麦穗
进行若干次操作后,如果得到的棋盘满足如下性质
1、每个格子都有至少一个麦穗
2、每个格子最多只能有p*p个麦穗
3、任意两个格子的麦穗数不同
如果满足以上三条,那么称这个棋盘是一个好棋盘,若只是构造一个好棋盘那就太没意思了,zzf想知道他能得到多少个不同的好矩阵
定义不同的矩阵即只要存在一个位置不同即是不同的
答案对998244353取模
输入描述:
第一行读入一个数p,表示这个棋盘的大小
输出描述:
输出一行包括一个数,表示好棋盘的个数
示例1
输入
2
输出
8
说明
样例解释 :
1 2
3 4
3 4
1 2
1 3
2 4
2 4
1 3
2 1
4 3
4 3
2 1
3 1
4 2
4 2
3 1
备注:
2 <= p <= 1e6, 保证p是质数

官方题解: 2(p!)2 2 ∗ ( p ! ) 2

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

const int MAXN = 2e5 + 10;
const LL mod = 998244353;

int main() {
    LL n, ans = 1;
    scanf("%lld", &n);
    for(LL i = 2; i <= n; ++i) {
        ans = (ans * i) % mod;
    }
    printf("%lld\n", (2 * (ans * ans) % mod) % mod);
    return 0;
}

D applese的生日

链接:https://www.nowcoder.com/acm/contest/80/D
来源:牛客网
题目描述
最可爱的applese生日啦,他准备了许多个质量不同的蛋糕,想请一些同学来参加他的派对为他庆生,为了不让一部分同学感到不爽,他决定把每个蛋糕都分割成几份(也可以不分割),使得最小的蛋糕的质量与最大的蛋糕的质量的比值不小于一个值。但是applese的刀功并不是很好,所以他希望切尽量少的刀数使得所得到的蛋糕满足条件。由于applese为了保证每一块蛋糕的质量和期望的没有偏差,所以他一刀只能切下一块蛋糕,即将一块蛋糕分成两块,同时,他不能一刀同时切两块蛋糕,也就是说,applese一次只能将一块蛋糕分割成两块指定质量的蛋糕,这两块蛋糕的质量和应等于切割前的蛋糕的质量。Applese还急着准备各种派对用的饰品呢,于是他把这个问题交给了你,请你告诉他至少要切割几次蛋糕
输入描述:
第一行包括两个数T,n,表示有n个蛋糕,最小的蛋糕的质量与最大的蛋糕的质量的比值不小于T
接下来n行,每行一个数wi,表示n个蛋糕的质量
输出描述:
输出包括一行,为最小切割的刀数
数据保证切割次数不超过500
示例1
输入
0.99 3
2000 3000 4000
输出
6
备注:
0.5 < T < 1
1 <= n <= 1000
1 <= wi <= 1000000

分析:这道题应该是最经典的优先队列维护问题,也是写的最崩溃的一道(wtm用二分最大化平均值写了快一天。。。)
主要是这个最小值是动态的,而且每块蛋糕分解块数未知,两个未知变量写的很头疼。。。优先队列维护这个关系,贪心选择最大值进行分解(块数递增,用一个整型变量标记),由于每次比较的对象都是当前最大和当前最小,一直贪心分解下去,直到找到满足比值T的条件;

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

struct node {
    double a;
    double b;
    int c;
    bool friend operator<(node x, node y) {
        return x.b < y.b;
    }
};

int main() {
    priority_queue<node> q;
    double T, minn = 100000000.0; int n;
    scanf("%lf %d", &T, &n);
    for(int i = 0; i < n; ++i) {
        double wi; node e;
        scanf("%lf", &wi);
        e.a = wi;
        e.b = wi;
        e.c = 1;
        q.push(e);
        minn = min(e.a, minn);
    }
    int ans = 0;
    while(q.top().b * T >= minn) {
        node e = q.top();
        q.pop();
        ans++;
        e.c++;
        e.b = e.a / (double)e.c;
        minn = min(e.b, minn);
        q.push(e);
    }
    printf("%d\n", ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值