A Turtle Puzzle: Rearrange and Negate
题目:
思路:阅读理解,其实就是求数组元素的绝对值之和
代码
#include <iostream>
using namespace std;
int n;
void solve() {
cin >> n;
int sum = 0;
for(int i = 1; i <= n; i ++ ) {
int x;
cin >> x;
if(x < 0) sum += -x;
else sum += x;
}
cout << sum << endl;
}
int main() {
int t;
cin >> t;
while(t -- ) {
solve();
}
return 0;
}
B turtle math: fast three task
题目:
思路:通过两种操作将一个数组的元素和变成3的倍数,由于操作可以给任意元素 + 1因此我们的操作最多不超过两次(连续加两个1结果一定是3的倍数) 我们可以枚举0,1次的情况,如果在0,1次都无法使数组合法,那么答案一定是2
代码:
#include <iostream>
using namespace std;
const int N = 1e5 + 10;
int n;
int a[N];
void solve() {
cin >> n;
for(int i = 1; i <= n; i ++ ) cin >> a[i];
int sum = 0;
for(int i = 1; i <= n; i ++ ) sum += a[i];
if(sum % 3 == 0) {
cout << "0" << endl;
return;
}
if((sum + 1) % 3 == 0) {
cout << "1" << endl;
return;
}
for(int i = 1; i <= n; i ++ ) {
if((sum - a[i]) % 3 == 0) {
cout << "1" << endl;
return;
}
}
cout << "2" << endl;
}
int main() {
int t;
cin >> t;
while(t -- ) {
solve();
}
return 0;
}
C. Turtle Fingers: Count the Values of k
题目:
思路:枚举所有的a^x, b^y,并判断此时的整型k是否合法。可以用快速幂优化
问题:一定要根据数据范围限制幂次的大小,否则运行时会溢出
代码:
#include <iostream>
#include <map>
using namespace std;
int a, b, l;
int qmi(int a, int b) {
int res = 1;
while(b) {
if(b & 1) res *= a;
a *= a;
b >>= 1;
}
return res;
}
void solve() {
map<int, int> ma;
cin >> a >> b >> l;
int ans = 0;
for(int i = 0; i <= 20 && qmi(a, i) <= 1e6; i ++ ) {
for(int j = 0; j <= 20 && qmi(b, j) <= 1e6; j ++ ) {
long long k = l / ((long long)qmi(a, i) * qmi(b, j));
if(k * (long long)qmi(a, i) * qmi(b, j) == l && !ma[k]) {
ma[k] ++;
ans ++;
}
}
}
cout << ans << endl;
}
int main() {
int t;
cin >> t;
while(t -- ) {
solve();
}
return 0;
}
D Turtle Tenacity: Continual Mods
问题:
思路:由于mod a的范围是0 ~ a - 1,因此如果一个序列是递增的,并且在mod过程中不出现0,那么最后结果一定不为零。将序列从小到大排序,如果a[1]的数值只有一个,那么(a[1] % a[2] < a[2]) % a[3] ...最后的结果肯定不为零。现在考虑a[1]数值不止一个的情况,此时a[1] % a[2] = 0,我们可以考虑在后续序列中找到一个数x,并且x满足x % a[1] != 0把这个数放在a[1]之前,此时x % a[1]后的序列就变成了第一种情况
代码:
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1e5 + 10;
int n;
int a[N];
void solve() {
cin >> n;
for(int i = 1; i <= n; i ++ ) cin >> a[i];
sort(a + 1, a + 1 + n);
if(a[1] != a[2]) cout << "YES" << endl;
else {
for(int i = 1; i <= n; i ++ ) {
if(a[i] % a[1] != 0) {
cout << "YES" << endl;
return;
}
}
cout << "NO" << endl;
}
}
int main() {
int t;
cin >> t;
while(t -- ) {
solve();
}
return 0;
}
E Turtle vs. Rabbit Race: Optimal Trainings
题目:
思路:用函数把最后值表示出来,发现是个开口向下的二次函数,并且对称轴是(2 * u + 1) / 1
此时二分答案得到r,并且判断r + 1与r哪个更加符合要求
代码:
#include <iostream>
#include <cmath>
using namespace std;
const int N = 1e5 + 10;
int n, q, cnt;
int a[N], sum[N];
void solve() {
cin >> n;
for(int i = 1; i <= n; i ++ ) {
cin >> a[i];
sum[i] = sum[i - 1] + a[i];
}
cin >> q;
while(q -- ) {
int ll, u;
cin >> ll >> u;
int l = ll, r = n;
while(l < r) {
int mid = l + r + 1 >> 1;
if(sum[mid] - sum[ll - 1] <= u) l = mid;
else r = mid - 1;
}
int a1 = abs(sum[l + 1] - sum[ll - 1] - u), a2 = abs(sum[l] - sum[ll - 1] - u);
if(l == n) cout << l << " ";
else {
if(a1 - 1 >= a2) cout << l << " ";
else cout << l + 1 << " ";
}
}
cout << endl;
}
int main() {
int t;
cin >> t;
while(t -- ) {
solve();
}
return 0;
}
问题:在最后判断r与r + 1哪个更加合适的时候,最开始写的判断条件一直是a1 <= a2代码一直WA,后看题解发现写的是a1 - 1 <= a2思考后发现,我们的对称轴中有小数0.5,由于自变量只能取到整数,所以在计算对称轴时下去整把0.5忽略了,那么在求谁距离对称轴更进的时候就相当于a1少减0.5,a2多减0.5最后差值是1。考虑到这里我发现二分时也用的对称轴二分,那么这个下去整会对二分结果产生影响吗?这个问题并不难,因为这里二分找的是小于等于对称轴的最大值,并且我们二分的答案一定是整数,所以最后的结果肯定是小于对称轴的最大值,只不过取不到等,不会影响案
思路2:在思路1的基础上稍微做出优化,可以发现当跑过u段后数值不会再增加,因为u + 1段能力值会变成0,因此二分出小于等于u的最小值。最后直接判断r与r + 1哪个带来的收益大
注意get函数可能爆int要用long long存储
代码2
#include <iostream>
#include <cmath>
using namespace std;
const int N = 1e5 + 10;
int n, q, cnt;
int a[N], sum[N];
long long get(long long x, long long u) {
return x * (u + u - x + 1) / 2;
}
void solve() {
cin >> n;
for(int i = 1; i <= n; i ++ ) {
cin >> a[i];
sum[i] = sum[i - 1] + a[i];
}
cin >> q;
while(q -- ) {
int ll, u;
cin >> ll >> u;
int l = ll, r = n;
while(l < r) {
int mid = l + r + 1 >> 1;
if(sum[mid] - sum[ll - 1] <= u) l = mid;
else r = mid - 1;
}
long long a1 = get(sum[l] - sum[ll - 1], u);
if(l + 1 <= n) {
long long a2 = get(sum[l + 1] - sum[ll - 1], u);
if(a1 >= a2) cout << l << " ";
else cout << l + 1 << " ";
} else cout << l << " ";
}
cout << endl;
}
int main() {
int t;
cin >> t;
while(t -- ) {
solve();
}
return 0;
}
F: Turtle Mission: Robot and the Earthquake
问题:
思路:最开始的思路是bfs。两张图,一张图dist记录当前位置与时间,另一张图g判断是否会与石头相撞。石头是向上偏移的,每次都判断石头的位置很麻烦,我们可以把石头当做参照物,石头每向上偏移,就相当于机器人向下移动一格。因此在图g中可以认为机器人每移动一次都会额外向下再走一次。但是写到最后发现这样有一个问题,有的点可能要经过两次 (详见样例2)。又发现题中规定m - 1列无障碍物,于是干脆不考虑dist图,在g图中同时计算dist,此时dist表示到最后一列任意一点的最短时间,最后遍历最后一列,求出最小值。由于实际石头是移动的,但是终点并不会移动,机器人到达m - 1列时实际上相对于终点多向下偏移了dist个长度,因此要把这个距离偏移回去,并且此时机器人要到终点可以向下也可以向上走,取最小值即可
代码:
#include <iostream>
#include <queue>
#include <cstring>
using namespace std;
const int N = 1e3 + 10;
typedef pair<int, int> PII;
int n, m;
int g[N][N], dist[N][N];
int dx[2] = {2, 1};
int dy[2] = {0, 1};
void bfs() {
queue<PII> q;
dist[0][0] = 0;
q.push({0, 0});
while(q.size()) {
auto t = q.front();
q.pop();
for(int i = 0; i < 2; i ++ ) {
int x = (t.first + dx[i]) % n;
int y = t.second + dy[i];
if(i == 0 && y + 1 <= m - 1) {//向下
if(dist[x][y] == 0x3f3f3f3f && g[x][y] != 1 && g[(x - 1 + n) % n][y] != 1) {
dist[x][y] = dist[t.first][t.second] + 1;
q.push({x, y});
}
}
if(i == 1) {//向右
if(y <= m - 1 && dist[x][y] == 0x3f3f3f3f && g[x][y] != 1) {
dist[x][y] = dist[t.first][t.second] + 1;
q.push({x, y});
}
}
}
}
}
void solve() {
memset(dist, 0x3f, sizeof dist);
cin >> n >> m;
for(int i = 0; i < n; i ++ ) {
for(int j = 0; j < m; j ++ ) {
cin >> g[i][j];
}
}
bfs();
bool flag = false;
for(int i = 0; i < n; i ++ ) {
if(dist[i][m - 1] != 0x3f3f3f3f) flag = true;
}
if(!flag) cout << "-1" << endl;
else {
int ans = 0x3f3f3f3f;
for(int i = 0; i < n; i ++ ) {
int a = ((i - dist[i][m - 1]) % n + n) % n;
ans = min(ans, dist[i][m - 1] + min(a + 1, n - 1 - a));
}
cout << ans << endl;
}
}
int main() {
int t;
cin >> t;
while(t -- ) {
solve();
}
return 0;
}
G