24牛客多校第一场
牛客多校第一场
按过题人数顺序
C.Sum of Suffix Sums
- 题意: 定义
- q个操作每次给出 t, v 代表每次从序列中删除后面t个后,加入一个v, 每次操作后输出
签到题,因为初始为空,且不会删除空序列,每次只加入一个数,模拟时间复杂度为
, 关键在于取模
int main()
{
int q; cin >> q;
vector<ll> a;
ll res = 0;
while(q --) {
ll t, v; cin >> t >> v;
while(t --) {
ll tmp = 1ll * a.size() * a.back() % mod;
res = (res - tmp % mod + mod) % mod;
a.pop_back();
}
a.push_back(v);
ll tmp = 1ll * a.size() * a.back() % mod;
res = (res + tmp) % mod;
cout << res << endl;
}
return 0;
}
H.World Finals
- 题意:两场比赛都给出了每场的参赛队伍名称,过题数,罚时,如果同一个参赛队伍这两场比赛全参加了那么可以任意分配两场都参加了的队伍的比赛场次的选择,问lzr010506最高可能的排名是多少?
也是签到题,分别计算出每场lzr010506在只参加某一场的队伍中的排名,因为参加两场的可以随便选择,取min就是答案,时间复杂度
struct Info {
string s;
int t, f;
bool operator < (const Info& _) const {
if(t == _.t) return f < _.f;
return t > _.t;
}
};
int main()
{
int n, m; cin >> n;
map<string, int> mp1, mp2;
vector<Info> comp1(n);
for(auto &[s, t, f] : comp1) {
cin >> s >> t >> f;
mp1[s] ++;
}
cin >> m;
vector<Info> comp2(m);
for(auto &[s, t, f] : comp2) {
cin >> s >> t >> f;
mp2[s] ++;
}
sort(comp1.begin(), comp1.end());
sort(comp2.begin(), comp2.end());
int rk1 = 1, rk2 = 1;
for(auto &[s, t, f] : comp1) {
if(s == "lzr010506") break;
if(mp2.find(s) == mp2.end()) rk1 ++;
}
for(auto &[s, t, f] : comp2) {
if(s == "lzr010506") break;
if(mp1.find(s) == mp1.end()) rk2 ++;
}
cout << min(rk1, rk2) << endl;
return 0;
}
A.A Bit Common
- 题意:求有多少长为 n 的元素是 [0,
) 的整数序列满足存在一个非空子序列的 AND 和是 1 答案对输入的正整数 q 取模 - 1 ≤ n, m ≤ 5000, 1 ≤ q ≤
数据范围提示应该是个
的做法或者 , 注意取模不是素数,不能用阶乘的关系,要用杨辉三角递推
排列其实从另一种角度可以看作是不同数的组合,可以不用考虑顺序
长度属于子序列的一个重要属性,从长度入手,枚举k从1到n长度是多少,对于每个长度是k的子序列,要满足与的值为1,只能是全奇数,考虑从n个位置挑k个位置放,因为偶数的位置不同,方案也不同,例如 3 2 1 4,3 1 2 4,这两种方案的子序列都是3 1,但是那两个位置放奇数,答案也就不同了,即,要做到不重不漏,考虑其他位置全偶数,不能有奇数,不然就是和 k + 1 个奇数, n - k 个偶数一样的情况,情况会重复,对于这k个奇数,他们的末尾一定是1,其他m - 1位,每位至少存在一个0
m-1 | m-2 | 1 | 0 | |
---|---|---|---|---|
1 | _ | _ | _ | 1 |
2 | _ | _ | _ | 1 |
k | _ | _ | _ | 1 |
根据容斥原理,每列至少有一个0可以用每列的排列组合减去全0的情况,即
, 这是每一列的情况,题目没说不能重复填数字,即可以有重复的,每列都有 的组合,有 列,乘法原理,即这部分奇数的答案就是
考虑偶数只能填剩下的位置,不需要组合数了,同理
m-1 | m-2 | 1 | 0 | |
---|---|---|---|---|
k + 1 | _ | _ | _ | 0 |
n - 1 | _ | _ | _ | 0 |
n | _ | _ | _ | 0 |
偶数就是随便组合了,但是最后一位必须是0,每列
, 共 列,答案就是 , 与奇数的贡献相乘即可
答案即为
ll C[N][N];
ll n, m, q;
ll ksm(ll a, ll b) {
a %= q;
ll res = 1;
while(b) {
if(b & 1) res = (res * a) % q;
a = (a * a) % q;
b >>= 1;
}
return res;
}
int main()
{
cin >> n >> m >> q;
for(int i = 1; i <= 5000; i ++) {
for(int j = 0; j <= 5000; j ++) {
if(!j || i == j) C[i][j] = 1;
else C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % q;
}
}
//cout << C[4][2] << endl;
ll res = 0;
for(int k = 1; k <= n; k ++) {//枚举奇数个数
// for(int j = 1; j <= i; j ++) {
// res = (res + ksm(i, j))
// }
ll odd = C[n][k] * ksm(ksm(2, k) - 1 + q, m - 1) % q;
ll eve = ksm(2, (n - k) * (m - 1)) % q;
res = (res + odd * eve % q) % q;
}
cout << res << endl;
return 0;
}
I.Mirror Maze
- 题意:有一个 n × m 的矩形镜子迷宫,镜子有 “\, /, -, |” 四种,每种镜子有特定的光线反射方向,注意直接通过镜子的情况不算被反射。
- 有 q 个询问,每个询问给定一个点光源 (x, y, dir),表示在 (x, y) 位置向dir 方向发射一束光线,问经过足够的时间之后,这束光线被多少个不
同的镜子反射过。
赛时当模拟写的,刚开始想的图论,发现建图能力不够,后来转向记忆化,能造的样例都能过,赛后只过了6%,还是存在大问题
因为是镜子,所以可以一直反射,如果不出界,最终会形成一个环,否则会形成一个链到外界。逆着看,就是从外面射进来得一束光,预处理最外层射进来的每一束光,处理完剩下的点一定在某个环中,再处理这个所在的环。所有处理过的点都标记一下,防止多次遍历,点在insert前要判断会不会被反射回来,时间复杂度
用set维护链。用一个数组存下来路径,能避免传参过多导致记忆化不好处理的麻烦,更新答案因为是记忆化归的过程,要逆着边更新边处理
同样用set也可以维护环,但是归的过程要把路径上的所有点更新,即先处理完数据再更新答案
struct node {
int x, y, d;
node(int x, int y, int d) : x(x), y(y), d(d) {}
};
char g[N][N];
map<string, int> mp;
int st[N][N][4], res[N][N][4];
int n, m, q;
vector<node> pt;
bool ref(int x, int y, int dir) {
char c = g[x][y];
if(c == '\\' || c == '/') return true;
if(c == '-' && dir <= 1) return true;
if(c == '|' && dir >= 2) return true;
return false;
}
void dfs(int x, int y, int dir) {
if(x < 1 || x > n || y < 1 || y > m) return ;
if(st[x][y][dir]) return ;
st[x][y][dir] = 1;
pt.push_back((node){x, y, dir});
char c = g[x][y];
if(c == '-') {
if(dir == 0) dfs(x + 1, y, 1);
else if(dir == 1) dfs(x - 1, y, 0);
else if(dir == 2) dfs(x, y -1, 2);
else dfs(x, y + 1, 3);
} else if(c == '|') {
if(dir == 0) dfs(x - 1, y, 0);
else if(dir == 1) dfs(x + 1, y, 1);
else if(dir == 2) dfs(x, y + 1, 3);
else dfs(x, y - 1, 2);
} else if(c == '\\') {
if(dir == 0) dfs(x, y - 1, 2);
else if(dir == 1) dfs(x, y + 1, 3);
else if(dir == 2) dfs(x - 1, y, 0);
else dfs(x + 1, y, 1);
} else if(c == '/') {
if(dir == 0) dfs(x, y + 1, 3);
else if(dir == 1) dfs(x, y - 1, 2);
else if(dir == 2) dfs(x + 1, y, 1);
else dfs(x - 1, y, 0);
}
}
void solve1(int x, int y, int dir) {//处理链,倒序判断,避免传参导致信息不好维护
pt.clear();
dfs(x, y, dir);
reverse(pt.begin(), pt.end());
set<PII> s;
for(auto &[x, y, d] : pt) {
if(ref(x, y, d)) {
s.insert({x, y});
}
res[x][y][d] = s.size();
}
}
void solve2(int x, int y, int dir) {//处理环, 环是循环,上面每个方向的2点的答案都一样
pt.clear();
dfs(x, y, dir);
reverse(pt.begin(), pt.end());
set<PII> s;
for(auto &[x, y, d] : pt) {
if(ref(x, y, d)) {
s.insert({x, y});
}
}
for(auto &[x, y, d] : pt) {
res[x][y][d] = s.size();
}
}
int main()
{
cin >> n >> m;
for(int i = 1; i <= n ;i ++) {
cin >> g[i] + 1;
}
for(int i = 1; i <= n; i ++) {
solve1(i, 1, 3);
solve1(i, m, 2);
}
for(int j = 1; j <= m; j ++) {
solve1(1, j, 1);
solve1(n, j, 0);
}
for(int i = 1; i <= n; i ++) {
for(int j = 1; j <= m; j ++) {
for(int k = 0; k < 4; k ++) {
if(!st[i][j][k]) {
solve2(i, j, k);
}
}
}
}
mp["above"] = 0;
mp["below"] = 1;
mp["left"] = 2;
mp["right"] = 3;
cin >> q;
while(q --) {
int x, y; string s; cin >> x >> y >> s;
int tmp = mp[s];
if(tmp == 0) x--;
else if(tmp == 1) x ++;
else if(tmp == 2) y --;
else y ++;
cout << res[x][y][tmp] << endl;
}
return 0;
}
本文作者:zouyua
本文链接:https://www.cnblogs.com/ZouYua/p/18308173
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· Obsidian + DeepSeek:免费 AI 助力你的知识管理,让你的笔记飞起来!
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了