A.
题目描述
有N个编号从1到N的国家。对于每个i=1,2,…,Ni=1,2,…,N,高桥手上有Ai单位的该国货币。
高桥可以重复进行以下操作任意次数,甚至零次:
- 首先,选择一个介于1和N−1之间的整数i。
- 然后,如果高桥至少有Si单位的ii国货币,他执行以下操作一次:
- 支付Si单位的i国货币,并获得Ti单位的(i+1)国货币。
输出高桥最终可能拥有的NN国货币的最大单位数。
解题思路
本题为简单模拟,将上一个国家的尽可能多的货币兑换成下一个国家的货币并计算总和。
解题代码
#include<bits/stdc++.h>
#define LL long long
#define endl "\n"
using namespace std;
const int N = 2e5 + 10;
LL a[N],s[N],t[N];
int n;
int main()
{
cin >> n;
for(int i = 1 ; i <= n ; i ++)
cin >> a[i];
for(int i = 1 ; i < n ; i ++)
cin >> s[i] >> t[i];
for(int i = 1 ; i < n ; i ++)
{
LL k = a[i] / s[i] * t[i];
a[i + 1] += k;
//cout << a[i + 1] << " ";
}
cout << a[n];
return 0;
}
B.
题目描述
有一个 HH 行 WW 列的网格。
网格中的每个单元格都是陆地或海洋,用长度为 WW 的字符串 S1,S2,…,SHS1,S2,…,SH 表示。设 (i,j)(i,j) 表示网格中从顶部开始第 ii 行、从左侧开始第 jj 列的单元格,如果 SiSi 的第 jj 个字符为 .
,则 (i,j)(i,j) 是陆地,如果字符为 #
,则 (i,j)(i,j) 是海洋。
约束条件保证网格周边的所有单元格(即满足 i=1i=1、i=Hi=H、j=1j=1、j=Wj=W 中至少一个的单元格)都是海洋。
高桥的飞船在网格中的一个单元格上坠毁。之后,他按照长度为 NN 的字符串 TT 中的指令移动了 NN 次。对于 i=1,2,…,Ni=1,2,…,N,TT 的第 ii 个字符描述了第 ii 次移动的方向如下:
L
表示向左移动一个单元格。也就是说,如果他在移动前在 (i,j)(i,j),移动后会在 (i,j−1)(i,j−1)。R
表示向右移动一个单元格。也就是说,如果他在移动前在 (i,j)(i,j),移动后会在 (i,j+1)(i,j+1)。U
表示向上移动一个单元格。也就是说,如果他在移动前在 (i,j)(i,j),移动后会在 (i−1,j)(i−1,j)。D
表示向下移动一个单元格。也就是说,如果他在移动前在 (i,j)(i,j),移动后会在 (i+1,j)(i+1,j)。
已知他路径上的所有单元格(包括他坠毁的单元格和他当前所在的单元格)都不是海洋。请输出可能是他当前位置的单元格数量。
解题思路
本题也是模拟就好,一次枚举每一个点作为起点,如果走过的路径全部都是陆地,那么答案+1 。
解题代码
#include<bits/stdc++.h>
#define LL long long
#define endl "\n"
using namespace std;
const int N = 510;
int h , w , n;
char l[N],s[N][N];
bool solve(int x , int y)
{
for(int i = 1 ; i <= n ; i ++)
{
if(s[x][y] == '#') return false;
if (l[i] == 'L') y -= 1;
if (l[i] == 'R') y += 1;
if (l[i] == 'U') x -= 1;
if (l[i] == 'D') x += 1;
}
if(s[x][y] == '.') return true;
else return false;
}
int main()
{
cin >> h >> w >> n;
for(int i = 1 ; i <= n ; i ++)
cin >> l[i];
for(int i = 1 ; i <= h ; i ++)
for(int j = 1 ; j <= w ; j ++)
cin >> s[i][j];
int ans = 0;
for(int i = 1 ; i <= h ; i ++)
for(int j = 1 ; j <= w ; j ++)
{
if(solve(i,j)) ans ++;
}
cout << ans;
return 0;
}
C.
题目描述
给定三个正整数 N,M 和 K。这里,N 和 M 是不同的。输出第 K 小的正整数,该数能被 仅且仅 由 N和 M 中的一个整除。
解题思路
本题二分答案,当前1 到 mid之间总共有个数符合条件(其中d为n,m的最小公倍数)。其意为在1 到 mid 之间符合条件的数,能被两者中任意一个整除,且不能被n,m的最小公倍数整除。
解题代码
#include<bits/stdc++.h>
#define LL long long
#define endl "\n"
using namespace std;
LL n,m,k;
LL gcd(LL a , LL b)
{
return b == 0 ? a : gcd(b , a%b);
}
LL solve(LL x , LL d)
{
return x/n + x/m - x/d * 2;
}
int main()
{
cin >> n >> m >> k;
LL d = n * m / gcd(n , m);
LL l = 0 , r = 1e18 , mid;
while(l <= r)
{
mid = l + (r - l) / 2;
if(solve(mid , d) < k) l = mid + 1;
else r = mid - 1;
}
cout << l ;
return 0;
}
D.
题目描述
给定一个长度为NN的由小写英文字母组成的字符串S。你将对字符串S执行Q次操作。 第i次操作(1≤i≤Q)由一对字符(ci,di)表示,对应以下操作:
- 用字符di替换S中所有出现的字符ci。
在所有操作完成后打印字符串S。
解题思路
这道题如果直接暴力求解会超时,但是如果将每次的更改,直接作用到字母表上,那么输出的时候将旧的字符串按照新的字母表输出就好。
解题代码
#include<bits/stdc++.h>
#define LL long long
#define endl "\n"
using namespace std;
const int N = 2e5 + 10;
char a[N];
int s[26];
int n,q;
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n;
for(int i = 0 ; i < 26 ; i ++) s[i] = i;
for(int i = 1 ; i <= n ; i ++)
{
cin >> a[i];
}
cin >> q;
while(q -- )
{
char c,d;
cin >> c >> d;
for(int i = 0 ; i < 26 ; i ++)
{
if(c - 'a' == s[i])
s[i] = d - 'a';
}
}
for(int i = 1; i <= n ; i ++)
{
cout <<(char) (s[a[i] - 'a'] + 'a');
}
return 0;
}
E.
题目描述
该铁路经过 N 个城市,每个城市都有一个站。不过,由于各个城市之间不能协调好,于是乘车每经过两个相邻的城市之间(方向不限),必须单独购买这一小段的车票。第 i 段铁路连接了城市 i 和城市 i+1(1≤i<N)。如果搭乘的比较远,需要购买多张车票。第 i 段铁路购买纸质单程票需要 Ai 博艾元。
虽然一些事情没有协调好,各段铁路公司也为了方便乘客,推出了 IC 卡。对于第 i 段铁路,需要花 Ci 博艾元的工本费购买一张 IC 卡,然后乘坐这段铁路一次就只要扣 Bi(Bi<Ai)元。IC 卡可以提前购买,有钱就可以从网上买得到,而不需要亲自去对应的城市购买。工本费不能退,也不能购买车票。每张卡都可以充值任意数额。对于第 i 段铁路的 IC 卡,无法乘坐别的铁路的车。
Uim 现在需要出差,要去 M 个城市,从城市 P1出发分别按照 P1,P2,P3,⋯ ,PM 的顺序访问各个城市,可能会多次访问一个城市,且相邻访问的城市位置不一定相邻,而且不会是同一个城市。
现在他希望知道,出差结束后,至少会花掉多少的钱,包括购买纸质车票、买卡和充值的总费用。
解题思路
差分数组存储访问的城市,前缀和计算每一个道路被经过多少次,答案就是每一条道路两个方案的最小值之和。
!!!切记记录两种方案的变量一定开long long !!!
解题代码
#include<bits/stdc++.h>
#define LL long long
#define endl "\n"
using namespace std;
const int N = 1e5 + 10;
LL a[N],b[N],c[N],p[N],s[N];
int n,m;
LL ans = 0;
int main()
{
cin >> n >> m;
for(int i = 1 ; i <= m ; i ++)
cin >> p[i];
for(int i = 1 ; i < n ; i ++)
{
cin >> a[i] >> b[i] >> c[i];
}
for(int i = 2 ;i <= m ; i ++)
{
int x = p[i - 1];
int y = p[i];
if(x > y) swap(x , y);
s[x] ++;
s[y] --;
}
for(int i = 1 ; i <= n ; i ++)
s[i] += s[i - 1];
for(int i = 1 ; i <= n ; i ++)
{
LL x = s[i] * a[i];
LL y = s[i] * b[i] + c[i];
ans += min(x , y);
}
cout << ans;
return 0;
}
F.
题目描述
爱丽丝和鲍勃正在玩一个游戏。他们有一个数组 a1,a2,…,an游戏包括两个步骤:
- 首先,爱丽丝将从数组中移除 最多 k 个元素。
- 其次,鲍勃将把数组中的 最多 x 个元素乘以 −1。
爱丽丝希望最大化数组元素的和,而鲍勃希望最小化。找到游戏结束后数组元素的和,假设两位玩家都采取最优策略。
解题思路
首先鲍勃选择的X个数,一定是最大的前X个数,那么总和一定会减少这个和的2倍。爱丽丝删除一个数,总和只会减少当前这个数值。所以答案的最优化策略就是,从爱丽丝删除0个数开始,直到爱丽丝删除K个最大的数循环,找到满足条件的最大值。
解题代码
#include<bits/stdc++.h>
#define LL long long
#define endl "\n"
using namespace std;
const int N = 4e5 + 10;
LL a[N];
LL t,n,k,x;
bool cmp(int m , int y)
{
return m > y;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> t;
while(t -- )
{
cin >> n >> k >> x;
LL up = 0 , down = 0 , sum = 0;
memset(a , 0 , sizeof(a));
for(int i = 1 ; i <= n ; i ++)
{
cin >> a[i];
sum += a[i];
}
sort(a + 1 , a + n + 1 , cmp);
for(int i = 1 ; i <= x ; i ++)
{
down += a[i];
}
LL ans = sum - down * 2;
for(int i = 1 ; i <= k ; i ++)
{
up += a[i];
down =down + a[i + x] - a[i];
ans = max(ans , sum - down * 2 - up);
}
cout << ans << endl;
}
return 0;
}