A.Leap Year(思维)
题意:
给你一个介于158315831583和202320232023之间的整数YYY。
求公历YYY年的天数。
在给定的范围内,YYY年的天数如下:
- 如果YYY不是444的倍数,则为365365365天;
- 如果YYY是444的倍数,但不是100100100的倍数,则为366366366天;
- 如果YYY是100100100的倍数,但不是400400400的倍数,则为365365365天;
- 如果YYY是400400400的倍数,则为366366366天。
分析:
判断年份是否为闰年。
- 如果nnn不能被444整除,那么不是闰年。
- 如果nnn可以被400400400整除,那么是闰年。
- 如果nnn不可以被100100100整除但是可以被444整除,那么是闰年。
否则就不是闰年。使用if-else语句判断即可。
代码:
#include<bits/stdc++.h>
using namespace std;
int main() {
int n;
cin >> n;
if (n % 4 != 0) {
cout << 365 << endl;
} else if (n % 400 == 0) {
cout << 366 << endl;
} else if ((n % 100 != 0) && n % 4 == 0) {
cout << 366 << endl;
} else {
cout << 365 << endl;
}
return 0;
}
B.Second Best(模拟)
题意:
给你一个长度为NNN的整数序列A=(A1,…,AN)A=(A_1,\ldots,A_N)A=(A1,…,AN)。这里的A1,A2,…,ANA_1,A_2,\ldots,A_NA1,A2,…,AN都是不同的。
在AAA中,哪个元素是第二大元素?
分析:
按照题意,使用map、pair或结构体对元素进行排序即可。
代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 1000100;
struct s {
int x, id;
bool operator<(const s &r) const {
return x > r.x;
}
} a[N];
int main() {
int n;
cin >> n;
for (int i = 1; i <= n; ++i) {
cin >> a[i].x;
a[i].id = i;
}
sort(a + 1, a + n + 1);
cout << a[2].id << endl;
return 0;
}
C.Transportation Expenses(二分答案)
题意:
有NNN人参加一项活动,第iii个人的交通费用是AiA_iAi日元。
活动组织者高桥决定设定交通补贴的最高限额为xxx。第iii个人的补贴为min(x,Ai)\min(x,A_i)min(x,Ai)日元。这里,xxx必须是一个非负整数。
高桥的预算为MMM日元,他希望所有NNN人的交通补贴总额最多为MMM日元,那么补贴限额xxx的最大可能值是多少?
如果补贴限额可以无限大,输出infinite。
分析:
本题我们分情况讨论,首先考虑答案为无限大的情况。对于这种情况可以先计算序列的总和和MMM比较,如果这个都小于等于MMM,那么肯定答案是无穷大。
对于不是无穷大的情况,考虑尝试枚举一个xxx,然后对于每一个xxx判断是否满足题目条件,然后记录最大的xxx,时间复杂度O(NM)O(NM)O(NM)。
对xxx的枚举我们采用二分,然后来判断,题目要求xxx的最大值,可以发现若此时的xxx为最大,那么对于每一个k≤xk\le xk≤x都可以满足题条件,而对于每一个k≥xk\ge xk≥x都不能满足题目条件,满足单调性。
代码:
#include<bits/stdc++.h>
typedef long long LL;
using namespace std;
const int N = 200005;
LL n, m, a[N], ans = -1e17;
bool check(LL x) {
LL res = 0;
for (int i = 1; i <= n; i++)
res += min(a[i], x);
return (res <= m);
}
int main() {
cin >> n >> m;
for (int i = 1; i <= n; i++)
cin >> a[i];
if (check(1e17)) {
cout << "infinite" << endl;
return 0;
}
LL l = 0, r = m;
while (l <= r) {
LL mid = (l + r) >> 1;
if (check(mid)) {
ans = mid;
l = mid + 1;
} else
r = mid - 1;
}
cout << ans << endl;
return 0;
}
D.AtCoder Janken 3(动态规划)
题意:
高桥和青木玩了NNN次剪刀石头布。注:在这个游戏中,石头赢剪刀,剪刀赢布,布赢石头。
青木的动作由长度为NNN的字符串SSS表示,字符串由"R"、"P"和"S"组成。SSS中的第iii个字符表示青木在第iii个对局中的出招:“R"表示"石头”,“P"表示"布”,“S"表示"剪刀”。
高桥的出招满足以下条件:
- 高桥从未输给过青木。
- 对于i=1,2,…,N−1i=1,2,\ldots,N-1i=1,2,…,N−1,高桥在第iii场对局中的出招与他在第(i+1)(i+1)(i+1)场对局中的出招不同。
确定高桥可能赢得的最大对局数。
可以保证存在一个满足上述条件的高桥出招顺序。
分析:
因为相邻两场对局出招不同,发现之前的对局存在后效性,考虑动态规划。
设dpi,[0/1/2]dp_{i,[0/1/2]}dpi,[0/1/2]表示当前为第i场对局,当前出的拳是R,P,SR,P,SR,P,S,最多可以赢多少局。
特殊计算一下dp1,[0/1/2]dp_{1,[0/1/2]}dp1,[0/1/2],dpi,jdp_{i,j}dpi,j的值可以通过dpi−1,kdp_{i-1,k}dpi−1,k转移来当且仅当k≠jk\neq jk=j,对于会输的出招直接赋值为一个极小值,取一个最大值然后增加对答案的贡献即可。
代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 1000100;
const int MIN_INF = -2e9;
int n;
int dp[N][3];
int main() {
cin >> n;
string s;
cin >> s;
s = ' ' + s;
if (s[1] == 'R') {
dp[1][0] = 0;
dp[1][1] = 1;
dp[1][2] = MIN_INF;
} else if (s[1] == 'P') {
dp[1][0] = MIN_INF;
dp[1][1] = 0;
dp[1][2] = 1;
} else {
dp[1][0] = 1;
dp[1][1] = MIN_INF;
dp[1][2] = 0;
}
for (int i = 2; i <= n; ++i) {
if (s[i] == 'R') {
dp[i][0] = max({dp[i - 1][1], dp[i - 1][2]});
dp[i][1] = max({dp[i - 1][0], dp[i - 1][2]}) + 1;
dp[i][2] = MIN_INF;
} else if (s[i] == 'P') {
dp[i][0] = MIN_INF;
dp[i][1] = max({dp[i - 1][0], dp[i - 1][2]});
dp[i][2] = max({dp[i - 1][0], dp[i - 1][1]}) + 1;
} else {
dp[i][0] = max({dp[i - 1][1], dp[i - 1][2]}) + 1;
dp[i][1] = MIN_INF;
dp[i][2] = max({dp[i - 1][0], dp[i - 1][1]});
}
}
cout << max({dp[n][0], dp[n][1], dp[n][2]}) << endl;
return 0;
}
E.Xor Sigma Problem(数学)
题意:
给你一个长度为NNN的整数序列A=(A1,…,AN)A=(A_1,\ldots,A_N)A=(A1,…,AN)。求以下表达式的值:
∑i=1N−1∑j=i+1N(Ai⊕Ai+1⊕…⊕Aj)\displaystyle\sum_{i=1}^{N-1}\sum_{j=i+1}^N(A_i\oplus A_{i+1}\oplus\ldots\oplus A_j)i=1∑N−1j=i+1∑N(Ai⊕Ai+1⊕…⊕Aj)
分析:
看到异或我们考虑拆位计算答案。设当前枚举到第kkk位,这一位有iii个0,jjj个1,因为异或为111要求两个异或的数互不相同,所以这一位对答案的贡献即为i×j×2ki\times j\times 2^ki×j×2k。
将所有位对答案的贡献累加即可。
代码:
#include<bits/stdc++.h>
typedef long long LL;
using namespace std;
const int N = 200001;
LL a[N], s[N];
int main() {
LL n;
cin >> n;
for (LL i = 1; i <= n; ++i) {
cin >> a[i];
s[i] = a[i];
a[i] ^= a[i - 1];
}
LL res = 0;
for (LL k = 0; k < 30; ++k) {
LL cnt = 0;
for (LL j = 0; j <= n; ++j)
cnt += a[j] >> k & 1;
res += cnt * (n - cnt + 1) * (1LL << k);
}
for (LL i = 1; i <= n; ++i)
res -= s[i];
cout << res << endl;
return 0;
}
赛后交流
在比赛结束后,会在交流群中给出比赛题解,同学们可以在赛后查看题解进行补题。
群号: 704572101,赛后大家可以一起交流做题思路,分享做题技巧,欢迎大家的加入。

1488

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



