2022北交新生赛总结

程心的挑战包括国际象棋策略、动态规划算法设计及高能粒子操作,同时涉及密码锁定和数据合并系统的分析。
摘要由CSDN通过智能技术生成

2023.2.25 AC 6/11 排名17

B. 三体·Round - 647号小宇宙

题目描述

“死神永生。”

顺着门一路行走,程心与关一帆进入了647号小宇宙,智子迎接了他们。

太阳系被二维化仿佛还在昨日,但已经是亿万年前的往事;DX3906下的蓝星被死线割裂的记忆,也随着沧海桑田般的变换葬在尘埃里。

程心以公元人的身份,经历了一生颠沛流离悲欢离合,目睹了人类文明的跌宕起伏消弭殆尽,主导了救赎,赋予了希冀,又亲手把一切努力葬送。身世浮沉恩恩怨怨是是非非,恍如昨日大梦一场,醒来内心也毫无悸动,只觉木然。

不过,在这与世隔绝的仙境,程心逐渐缓和了她恐惧不安的情绪,和关一帆和智子在一起,多少也有一个陪伴。除了耕作,学习新的知识,书写《时间之外的往事》,程心还培养起了一个爱好:下国际象棋。

这来自上古西方的游戏,用64个格子、32个棋子,在黑白交加的棋盘上演绎着王国腾飞到衰落,又或者是破碎到复兴,她觉得,这像极了过去。

程心当然不会去和智子下棋,毕竟和机器下棋毫无胜算;然而关一帆的棋艺远在程心之上,纵使她绞尽脑汁竭尽全力也赢不了他一局。于是程心决定研究一些别的与国际象棋有关的问题。

(以下进入正文)

程心在小宇宙的微型电脑中查阅公元时期资料时,定位关键词21世纪、国际象棋、算法竞赛,她搜到了如下题目:

[SCOI2005] 互不侵犯 :研究国王互相攻击的问题

[2019年雅礼集训] ROOK:研究车互相攻击的问题

[USACO1.5] Checker Challenge:研究皇后相互攻击的问题

[SCOI2005] 骑士精神 :研究骑士的行走问题

她发现,没有任何研究象(主教)和兵的问题。她觉得兵的问题没有什么可以研究的,所以她决定研究象的互相攻击问题。

国际象棋中的象的吃子规则是,只能沿着所在的斜线吃子。以6x6棋盘中的一个象为例,这个象可以攻击到箭头表示的这四个斜线方向任何一个格子。

具体地,程心提出了这样一个问题:

对于一个大小为N×N的棋盘,在这个棋盘上放置K个国际象棋中的象,并且这K个象不能互相攻击到,求有多少种放置的方案数。两种方案数不同,当且仅当这两种方案中,存在一个格子满足第一种方案在这个格子上有象,而第二种方案在这个格子上没有象。

程心觉得这是一个好的问题,她把关一帆和智子叫过来一起研究。但是智子非常不屑,因为以她的运算能力,可以把所有情况直接穷举出来。但是为了让两个人类朋友接受她的运算结果,她需要自己设计一个高效的算法。由于数字可能太长,只需要提供答案对998244353取模的结果即可。

智子想知道,这个算法应该如何设计呢?

输入数据

第一行两个数字 N,K,表示棋盘规模和象的个数。

2≤N≤10^3,1≤K≤2N−2

输出数据

一行一个数字,表示方案数对998244353取模的结果。


tag

动态规划,思维,组合数学

思路

首先,黑格上的象和白格上的象不可能相互攻击到。所以把黑格白格分开考虑。最外层枚举白格放m个象,那么黑格就要放K-m个象。那么考虑求出白格象的方案数,黑格象的方案数,再相乘即可。黑格白格对等,所以只要求出t(1<=t<=K)个象放在白格且不互相攻击的方案数。

斜线难考虑,但可以考虑从左下到右上的方向看所有白格,再调整顺序,那么这时可以把白格们看成N行,每列数目为1,1,3,3,5,5,…,

把这些行左对齐,然后从右往左进行编号,再DP。设f[i][j]表示前i列,共放了j个象的方案数。由于随着列数增加,每列能放的象的数目在增加,如果第i列有p个格子,那么第i列要么不放,要么放一个象,有p-j种方法。所以f[i][j]=f[i-1][j]+(p-(j-1))f[i-1][j-1],这样白格放m个象的数目就是f[列数][m],就可以统计答案了。复杂度O(NK)

代码



D. 尽管如此世界依然美丽

题目描述

与其站在原地思考

不如一步一步地往前走吧

就算昨天的足迹会消失不见

哪怕通往明天的道路隐没在黑暗中

即便如此……也不要一味地回首过去

不要对未来悲观失望

只需尽情地感受当下

因为不管你如何反抗

时间总是会不断推着你前进

               --珂朵莉

珂朵莉最近遇到了一道简单的数学难题,她询问了 lovekdl,然而 lovekdl也不会这道题,于是珂朵莉向聪明的你求助,请你帮她解决吧!

给定正整数n,请你统计一下满足GCD(i,j)×LCM(i,j)=⌊nk⌋的(i,j,k)数量(1≤i,j,k≤n)。

注: ⌊x⌋表示对 x向下取整,比如 ⌊1.145⌋=1。GCD(x,y) 表示 x 与 y 的最大公约数,LCM(x,y) 表示 x 与 y的最小公倍数。1≤n≤10^9。

输入数据

第一行为一个整数 n。1≤n≤10^9。

输出数据

输出共一行,第一行输出一个整数表示满足条件的 (i,j,k)的总数。


tag

思维

思路

首先,GCD(i,j)*LCM(i,j) = i*j

然后,对于n/k向下取整,可以整除分块,枚举一段k ∈区间[l, r]时,n/k向下取整的值为d。

那么我们要求的就是i*j = d

显然 i 的所有取值就是d的所有因数,所以(i,j)的取值就是d的因数个数,再把因数个数乘上区间长度(r-l+1)就是该区间的(i,j,k)数量。答案就是整除分块每一段区间的(i,j,k)加起来

代码



F. 助手酱想要知道密码

题目描述

作为 Labman−004,Christina 当然有权使用 电话微波炉(暂定) 来发送 D-Mail。

但是 电话微波炉(暂定) 是 lab 的重要战略资源,为了让非 lab 成员不能随意使用,凤凰院凶真改造了它,给它加上了密码锁。

密码锁的密码是动态的。每个 Labman 都有一个手表,上面会有数个动态码指示当天 电话微波炉(暂定) 的密码为多少,获得密码的规则如下:

动态码共有 11个,前 10个数为 筛码 Pi(0≤i≤9),最后一个数为 位码 N,密码为从 1开始第 N个不能被任何一个 Pi整除的数。

Christina 虽然是提出了时间旅行可能性的天才,但她并不是很擅长数学,而且 N实在太大了!于是她找到了你,希望你能帮她算出密码。Christina 每天都会来找你,直到她不需要再使用 电话微波炉(暂定) 为止,因此你需要回答她的 Q次询问。

这个密码可能会很大,为了让 Labman 们不至于花太多时间在输密码上,真正的密码为上述计算结果对 998244353取模。

输入数据

第一行为一个整数 Q,为Christina的询问次数。1≤Q≤100。接下来 Q 行每行有 11个数字,前 10个数字为筛码,最后 1 个为位码。题目保证 ,且答案一定存在。注意 ∏表示连乘,即 P0,P1,...,P9的乘积。

输出数据

输出共 Q 行,每行输出一个整数,表示求得的密码。(注意对 998244353取模)


tag

思维

思路

注意到题目里的特殊条件:𝑃𝑖的积小于等于10^18;设𝑃𝑖的积为X,可以证明对于任意x,x+kX(k为整数)同时能或不难被某个P𝑖整除,因此我们可以先算出在一个X周期内有多少会被计数的数,然后在最后一个不完整的区间里二分得到最终的数。

这题的N可以达到10^180,不能直接进行计算,但注意到答案仅要求输出在998244353模意义下的结果。我们可以先算出N%X,然后在模998244353下计算(N-N%X)/X,就可以得到区间数。

直接使用高精度同样也可以计算出答案,复杂度与上述做法基本相同,常数会偏大。复杂度

代码



G. 挑战

题目描述

一共有 n人挑战 boss,boss 一共 m体力。每个人每轮能使自己的体力减少一点,同时让 boss 的体力减少一点。第 i人有 ai点体力,当体力归零的时候需要休息 bi轮之后将体力恢复到 ai(期间不能攻击boss)。当 boss 的体力减少到 0 的时候,boss 被击败,他们想知道此时的轮数。

输入数据

第一行两个整数 n,m代表人数和boss血量。1≤n≤10^5,1≤m≤10^6。第二行 n个整数 ai,代表第i人血量。1≤ai≤10e6。第三行 n个整数 bi,代表第i人恢复时间,1≤bi≤10^6。

输出数据

输出共一行,第一行输出一个整数代表 boss 体力减少到 0

的时候的轮数。


tag

二分

思路

考虑二分答案,每次验证前多少轮每个人能造成的伤害和是否大于boss血量。第i人每ai+bi轮可以造成ai点伤害,剩下的轮数可以造成ai与轮数较小值的伤害。因此可以O(n)计算前多少轮每个人能造成的伤害和。总复杂度O(nlogm),另外最大轮数为1^12。

代码



I. rankYu的高能装置

题目描述

rankYu偶然发现了一个神秘的高能装置,这个装置包含 n个高能粒子。

由于高能粒子非常不稳定,装置随时可能爆炸。rankYu发现,当所有粒子的能量值相同时,装置的安全性最高。

rankYu有两种操作:

  • 所有粒子能量值 +1

  • 所有 能量值为偶数的粒子能量值变为原来的1/2试构造一个操作序列把所有粒子的能量值变成相同。

你最多可以操作 200次(不必最小化操作次数)。

可以证明,必定存在这样的操作序列。如果有多种合法的操作方案,你只需要输出任意一种即可。

输入数据

第一行一个整数 n,表示高能粒子的数量。1≤n≤10e5。接下来一行 n个整数 a1,a2,…,an,ai表示第 i个高能粒子的初始能量值。1≤ai≤10^18。

输出数据

输出一个字符串,表示你的操作序列。

+ 表示 +1 操作。

/ 表示 /2 操作。

! 表示操作结束。


tag

思维

思路

由于数的范围较大10^18,因此缩小数的范围仅能依靠/2实现

对于一个值为10^18数量级的数𝑎𝑖,最少需要log(𝑎i)次才能实现变为1。(约为60次左右)

总共200次操作限制,因此考虑平均每3次,将所有数减半,如若可以实现,则在200次以内,能够保证所有数变为1。

对于偶数来说,一次/2可以让所有偶数减半,对于奇数来说,先+1后/2,即可将所有奇数减半。

因此可以构造形如/+/的形式,这样用3次操作,即可以将所有数减半。最终满足题意(+//等都可以)

代码


#include <iostream>
#include<cstring>
#include<cmath>
#include<cctype>
#include<algorithm>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
using namespace std;
#define LL long long 
LL a[100010];
void solve() {
    int n;
    cin >> n;
    for (int i = 0; i < n; ++i) cin >> a[i];
    for (int i = 1; i <= 66; ++i) cout << "+//";
    cout << '!';
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int _t;
    _t = 1;
    //cin >> _t;
    while (_t--) {
        solve();
    }
    return 0;
}

J. 数据合并系统

题目描述

W-34接触到了一种数据合并系统。这个系统通过数据的标识码来识别数据,并且能将具有相关性的数据的标识码合并为相同的数。现在有 n个数据输入到系统中,同时系统设定好的工作常数为 k 。开始工作后,系统会不断地执行以下操作:选择两个数 l,r,将所有识别码数值范围为 [l,r] 的数据的识别码修改为 j ,表示它们具有相关性;W-34对系统的工作过程产生了兴趣,他会在系统工作的过程中时不时地问你,有多少对数据间的识别码数值之和为 k 。

输入数据

第一行三个整数 n,q,k,表示数据数量,事件总数和设定的工作常数。1≤n≤10^5 , 1≤q≤2⋅10^5 , 1≤k≤10^6。

第二行 n个整数,代表每个数据的识别码 ai。0≤ai≤10^6。接下来 q行,按时间先后顺序每行表示一个事件。每行的格式形如 1 l r j 或 2,分别表示系统的一次操作或 W-34 的一次询问。0≤l≤r≤10^6 ,0≤j≤10^6。

输出数据

对每个询问操作,输出一行一个整数表示问题的答案。


tag

思维

思路

可以发现,每次修改操作将会对数值范围为[l,r]的数变为同一个数。也就是说,在不断进行修改的过程中,不同的数将会越来越少。(每次修改操作后,数的种类不变或者减少)

因此,考虑暴力对修改范围[l,r]中存在的每一类数进行修改,于是考虑用set进行遍历。

那该怎样求出答案?在处理前,先O(n)求出答案,考虑在每次的修改中,动态维护答案。

对于每一个需要修改的数i,在答案上减去他原先可造成的贡献(k-i)的个数*i的个数,最后再加上新的贡献(k-j)的个数*新增加的j的个数

(特殊处理j*2==k的情况)

代码


#include <iostream>
#include<cstring>
#include<cmath>
#include<cctype>
#include<algorithm>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
using namespace std;
#define LL long long 
LL num[1000010];
set<int> s;
void solve() {
    int n, q, k;
    LL ans = 0;
    cin >> n >> q >> k;
    for (int i = 1; i <= n; ++i) {
        int x;
        cin >> x;
        if (x > k) continue;
        s.insert(x);
        num[x]++;
        if (2 * x == k) ans += num[x] - 1;
        else ans += num[k-x];
    }
    for (int i = 1; i <= q; ++i) {
        int op;
        cin >> op;
        if (op == 1) {
            int l, r, c;
            cin >> l >> r >> c;
            int sum = 0;
            for (auto j = s.lower_bound(l); j != s.upper_bound(r);) {
                int x = *j;
                if (2 * x == k) ans -= num[x] * (num[x] - 1) / 2;
                else  ans -= num[k - x] * num[x];
                sum += num[x];
                num[x] = 0;
                s.erase(j++);
            }
            if (c > k) continue;
            s.insert(c);
            if (2 * c == k) ans += (num[c]+num[c]+sum-1)*sum/2;
            else ans += num[k - c]*sum;
            num[c] += sum;
        }
        else {
            cout << ans << '\n';
        }
    }
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int _t;
    _t = 1;
    //cin >> _t;
    while (_t--) {
        solve();
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值