A-超市里扫货
https://ac.nowcoder.com/acm/contest/46597/A
题意:Flash要按照顺序购买商品,并且他的购物车有最大上限,装不下了就去卸货,问要多少次才能全部买完
分析:水题,遍历即可
#include <bits/stdc++.h>
using namespace std ;
const int N = 1e5 + 8 ;
int num[N] ;
using ll = long long ;
int main(){
int n , v ;
cin >> n >> v ;
for(int i = 0 ; i < n ; i ++){
cin >> num[i] ;
}
ll ans = 0 ;
ll tmp = 0 ;
for(int i = 0 ; i < n ; i ++){
tmp += num[i] ;
if(tmp > v) ans ++ , tmp = 0 , tmp += num[i] ;
}
if(tmp > 0) ans ++ ;
cout << ans << '\n' ;
return 0 ;
}
B-柜台结账
https://ac.nowcoder.com/acm/contest/46597/B
题意:Flash去买东西但是傻乎乎的不会判断“四舍五入”后的结果比原来的大还是比原来的小:
1.当小数部分>0.5时,向上取整
2.当小数部分<0.5时,向下取整
3.当小数部分==0.5时,取离这个数最近的偶数
分析:容易知道,当小数部分>0.5时,结果肯定大;小数部分<0.5时,结果肯定小;当小数部分==0.5时,判断整数部分的最后一位是奇数还是偶数即可。因为输入的是字符串,比赛时>0.5的部分想当然的处理了,结果WA了一发,痛苦
PS:比赛当天是笔者生日,出题人是我师哥,所以这题的YXGG其实就是我哈哈哈哈哈哈哈哈哈,谢谢HR师哥
#include <bits/stdc++.h>
using namespace std ;
bool judge(string s){
for(int i = 1 ; i < s.size() ; i ++){
if(s[i] != '0') return true ;
}
return false ;
}
int main(){
string a1 , a2 ;
cin >> a1 >> a2 ;
if(a2[0] > '5' || (a2[0] == '5' && judge(a2))) cout << "Happy birthday to MFGG\n" ;
else if(a2[0] < '5' && a2[0] > '0'){
cout << "Happy birthday to YXGG" << '\n' ;
}
else if(a2[0] == '0') cout << "PLMM" << '\n' ;
else {
long long t = a1.size() - 1 ;
int tmp = a1[t] - '0' ;
if(tmp % 2 == 0) cout << "Happy birthday to YXGG" << '\n' ;
else cout << "Happy birthday to MFGG\n" ;
}
return 0 ;
}
C-小猫觅食
https://ac.nowcoder.com/acm/contest/46597/C
题意:小猫咪想吃小鱼干,PLMM身上带了小鱼干,PLMM只能在曼哈顿距离<=r1的范围内活动,而小猫咪能闻到曼哈顿距离<=r2范围内的小鱼干,当小猫咪闻到小鱼干的味道的时候,PLMM就停止移动,小猫咪就直接往PLMM的方向移动,并且小猫咪并没有移动范围
分析:对小猫咪和PLMM分别走一遍BFS即可,结果就是所有满足条件的点去最小值
#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std ;
const int N = 1e3 + 8 ;
char mp[N][N];
int n , m ;
int r1 , r2 ;
int dis[2][N + 8][N + 8] ;
bool judge(int x , int y){
if(x < 1 || x > n || y < 1 || y > m) return false ;
return true ;
}
int getlen(int a , int b , int c , int d){
return abs(a - c) + abs(b - d) ;
}
const int dx[] = {-1 , 0 , 1 , 0} ;
const int dy[] = {0 , 1 , 0 , -1} ;
void bfs(int cat , int x , int y , int r){
struct node{
int x , y ;
} ;
queue<node> q ;
node fir ;
fir.x = x , fir.y = y , dis[cat][x][y] = 0 ;
q.push(fir) ;
while(!q.empty()){
auto t = q.front() ;
q.pop() ;
for(int i = 0 ; i < 4 ; i ++){
int tx = t.x + dx[i] ;
int ty = t.y + dy[i] ;
if(judge(tx , ty) && mp[tx][ty] == '.' && dis[cat][tx][ty] == inf && getlen(tx , ty , x , y) <= r){
node tmp ;
tmp.x = tx , tmp.y = ty ;
dis[cat][tx][ty] = dis[cat][t.x][t.y] + 1 ;
q.push(tmp) ;
}
}
}
}
int main(){
cin >> n >> m >> r1 >> r2 ;
for(int i = 1 ; i <= n ; i ++){
for(int j = 1 ; j <= m ; j ++){
cin >> mp[i][j] ;
}
}
int mx , my ;
memset(dis , 0x3f , sizeof dis) ;
for(int i = 1 ; i <= n ; i ++){
for(int j = 1; j <= m ; j ++){
if(mp[i][j] == 'P') bfs(0 , i , j , r1) ;
else if(mp[i][j] == 'M') bfs(1 , i , j , inf) , mx = i , my = j ;
}
}
int ans = inf ;
for(int i = 1 ; i <= n ; i ++){
for(int j = 1 ; j <= m ; j ++){
if(getlen(i , j , mx , my) <= r2){
ans = min(ans , dis[0][i][j] + dis[1][i][j]) ;
}
}
}
if(ans == inf) ans = -1 ;
cout << ans << '\n' ;
return 0 ;
}
D-石油大亨
https://ac.nowcoder.com/acm/contest/46597/D
题意:题目背景来源于红警,因为师哥最近成迷于红警游戏而且天天直播,给出他的B站链接The___Flash的个人空间_哔哩哔哩_bilibili
兵营生产一个工程师要花费时间et,并且需要花费金钱ec;地图上总共有n块油田,Flash想要占领全部的油田,工程师占领第i个油田需要花费的时间为
,并且占领过后每秒能带来价值为p的收益,Flash初始金钱为s。问顺序占领所有油田需要多长时间
分析:模拟题,师哥都亲自承认这道题很恶心。我就直接看了师哥的题解代码,加上了点注释,一看就懂,注意金钱可能会爆ll
#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std ;
using ll = long long ;
const int N = 1e5 + 8 ;
ll n , ec , et , p , s ;
int t[N] ;
void solve(){
if(s < ec){
cout << -1 << '\n' ;
return ;
}
queue<ll> q ; //存放的是工程师占领下一个油田的结束时间
ll cur_time = 0 ; //当前时间
ll oil_cnt = 0 ;
for(int i = 1 ; i <= n ; i ++){ //枚举每个油田,每次循环都是新开了一片油田
ll nxt_time = (i == 1 ? 0 : cur_time + et) ; // 下一次开始训练工程师的时间
while(!q.empty() && q.front() <= nxt_time){ //如果下次训练工程师前有工程师占领了新的油田
if(s < inf) s += oil_cnt * (q.front() - cur_time) * p ;
cur_time = q.front() ;
q.pop() ;
oil_cnt ++ ;
}
if(cur_time < nxt_time){ //计算当前时间到下次训练工程师的时间之间增加的money
if(s < inf) s += (nxt_time - cur_time) * oil_cnt * p ;
cur_time = nxt_time ;
}
if(s < ec){ //如果钱不足以训练新的工程师
while(!q.empty() && s + oil_cnt * (q.front() - cur_time) * p < ec){ //如果期间还能占领新的油田
s += oil_cnt * (q.front() - cur_time) * p ;
cur_time = q.front() ;
q.pop() ;
oil_cnt ++ ;
}
ll wait_time = (ec - s + (ll)oil_cnt * p - 1) / oil_cnt / p ; //使得s >= ec需要的时间,并且上取整
s += wait_time * p * oil_cnt ;
cur_time += wait_time ;
}
s -= ec ;
q.push(cur_time + et + t[i]) ;
}
cout << cur_time + et + t[n] << '\n' ;
}
int main(){
cin >> n >> ec >> et >> p >> s ;
for(int i = 1 ; i <= n ; i ++){
cin >> t[i] ;
}
solve() ;
return 0 ;
}
E-排队
https://ac.nowcoder.com/acm/contest/46597/E
题意:求出一个序列全排列中逆序对的和是多少
分析:可以注意到,一对不同的数
,对于整个序列的全排列贡献值为
(以1 和 2 举例,一个序列中的所有权排列肯定归为两种形式:....1....2..... 和 ....2....1.....,其中只有2 1 的组合产生贡献,所以一对不同的数产生的贡献就是
),答案就是求出序列中所有不同的对数乘以
即可
#include <bits/stdc++.h>
using namespace std ;
using ll = long long ;
const int N = 1e5 + 8 ;
const int mod = 1e9 + 7 ;
ll a[N] ;
int cnt[N] ;
int main(){
int n ;
cin >> n ;
ll ans = 0 ;
int a ;
for(int i = 1 ; i <= n ; i ++){
cin >> a ;
ans = ans + (i - ++cnt[a]) % mod ;
ans = ans % mod ;
}
for(int i = 3 ; i <= n ; i ++){
ans = (ans * i) % mod ;
}
cout << ans << '\n' ;
return 0 ;
}
F-选座椅
https://ac.nowcoder.com/acm/contest/46597/F
题意:电影院中有n个座位,所有人都坐在一起,即所有人的座位是[1,2,...,n]的连续子序列。但是同时给出三个条件
,(共有3*m个要求)要求至少有一个人坐在
要求的座位中,且同时满足m个要求,所以总共是有m个条件,并且每个条件分为三个小点
,满足其中的一个就算做满足第i个条件。问坐1个人,2个人...n个人有多少不同的座位分配方式
分析:双指针+差分。我们可以注意到,如果区间[l,r]满足m个要求,那[l,r+1]也肯定满足m个要求。我们用ans[i]来代表坐i个人有多少不同的座位分配方式。同时定义n个vector,v[i]代表的是i这个座位出现在了哪些条件里,用cnt[i]来代表第i个条件满足了几个,用tot来代表满足了几个条件,如果++cnt[i] == 1就代表是第一次满足这个条件 , tot ++;同理,如果--cnt[i] == 0就代表第i个条件不再被满足,tot -- ; 当所选区间满足m个条件时,那么就说明[l,r]到[l,n]中的所有区间都满足条件,那么对应到ans上就是长度为r - l + 1,到 n - l + 1的长度都满足条件,这里就可以用差分来解决,所以本质上就是双指针取消寻找满足m个条件的区间,再在这个基础上将所有满足条件的区间长度+1. 因为还要求出方案总数,前面求的是满足条件的位置,求座位方式再乘以阶乘即可
#include <bits/stdc++.h>
using namespace std ;
using ll = long long ;
const int N = 1e5 + 8 ;
const int mod = 1e9 + 7 ;
std::vector<int> v[N];
int n , m ;
int tot ;
ll cnt[N] , ans[N] ;
void add(int x){
for(auto i : v[x]){
if(++cnt[i] == 1) tot ++ ;
}
}
void del(int x){
for(auto i : v[x]){
if(-- cnt[i] == 0) tot -- ;
}
}
int main(){
cin >> n >> m ;
for(int _ = 1 ; _ <= 3 ; _ ++){
for(int i = 1 ; i <= m ; i ++){
int x ;
cin >> x ;
v[x].push_back(i) ;
}
}
for(int l = 1 , r = 0 ; l <= n ; l ++){
while(r + 1 <= n && tot < m){
add(++ r) ;
}
if(tot == m) ans[r - l + 1] ++ , ans[n - l + 1 + 1] -- ;
del(l) ;
}
ll fac = 1 ;
for(int i = 1 ; i <= n ; i ++){
fac = (fac % mod * i % mod) % mod ;
ans[i] += ans[i - 1] ;
cout << (ans[i] % mod * fac % mod) % mod << " \n"[i == n] ;
}
return 0 ;
}
特别感谢HR师哥将我的生日祝福写进比赛里,HR师哥嘎嘎强
[水平有限,欢迎指正]
621

被折叠的 条评论
为什么被折叠?



