You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
4.0 KiB
4.0 KiB
P9748 [CSP-J 2023]
小苹果
第一题,一般不会用到什么算法,函数什么的都不会用到
1、看数据范围,测试点1 \sim 2,n<=10
,此时可以打表
if (n == 1)
res = 1, day = 1;
else if (n == 2)
res = 2, day = 2;
else if (n == 3)
res = 3, day = 3;
else if (n == 4)
res = 3, day = 1;
else if (n == 5)
res = 4, day = 4;
else if (n == 6)
res = 4, day = 2;
else if (n == 7)
res = 4, day = 1;
else if (n == 8)
res = 5, day = 5;
else if (n == 9)
res = 5, day = 3;
else if (n == 10)
res = 5, day = 1;
用人脑算一下,然后写上去,这就是打表,可以得20
分。
2、3 \sim 5 \ n<=1000
此时可以开一个bool
数组,每次遍历n*n=1000000
次,可以过,又得到20
分。
当在把st[n]
设置为true
时,记录现在是第几天就行了。
#include <bits/stdc++.h>
using namespace std;
const int N = 1000010;
int st[N];
int cnt; // 已经取出的个数
int day; // 第n个苹果是第day天被取走的
int all; // 一共需要多少天
int main() {
// freopen("apple.in", "r", stdin);
// freopen("apple.out", "w", stdout);
int n;
cin >> n;
while (true) {
// 模拟每一天
all++;
int c = 0;
for (int i = 1; i <= n; i++) {
if (st[i]) continue;
c++;
if (c % 3 == 1) { // 找规律,1,4,7,10...出列
st[i] = 1;
cnt++; // 又出队一个
if (i == n) day = all; // 记录n是哪天出队的
}
}
if (cnt == n) break; // 如果出队数量达标就完事
}
// 输出一共需要多少天,取出第n号在第几天
cout << all << " " << day << endl;
return 0;
}
3、6 \sim 7
10^6
的数据范围
明显刚才O(N*N)
的做法不行,太慢了。
此数据有特殊性质:小苞第一天就取走编号为 n
的苹果。
按题意假设有81
个苹果,实际上变化的是
81->81*2/3=54->54*2/3=36 ->24*2/3=16 -> 16 * 2/3 = ...
你会发现下降的特别快,也就是一次减少2/3
,那么2
次就是减少2/3*2/3=4/9
,而4/9<1/2
,也就是两次减少1
半
每次减少1
半是log_2{N}
,两次减少一半,就是2*log_2{N}
,也就是是一个logN
的时间复杂度,并不是O(N*N)
,是O(2NlogN)
也就是说,上面的代码可以得到70
分!
4、数学解法
#include <bits/stdc++.h>
using namespace std;
int n, all, day;
int main() {
cin >> n;
while (n) { // 剩余苹果数量
all++; // 新的一天
if (day == 0 && n % 3 == 1) day = all; // 判断编号n的苹果第几天被取走
n -= ceil(1.0 * n / 3);
// 上取整公式
// n = n - (n + 2) / 3; // 剩余苹果数
}
// 输出总天数 和 第n 个苹果第几天被取走
cout << all << " " << day << endl;
return 0;
}