前言
如果认为自己代码没问题,换行问题,边界问题等都处理了还是不行,可以试试交 C++(GCC9) 该类型,因为部分题目是 UVA 上的老题,可能不支持新版本的 C++。
如果提交UNKNOWN ERROR
,应该是没绑定UVA账号,洛谷右上角个人设置里去填写注册一下即可。
除法 Division
思路
这个题一定要注意输出格式!!!,最后一行 \(0\) 不能输出多余空格,建议是打个标记在最开头输出换行。
因为数字只有 \(0\sim 9\),所有可以考虑全排列,但是对每次 \(n\) 都去跑全排列这个时间代价是 \(10!\) 级别的,难以承受,细想可以发现,其实对于每个 \(n\) 来说,有很多不必要的排列是不用去枚举的,所以我们可以预处理出 \(0\sim 9\) 的排列,然后根据前 \(5\) 位和后 \(5\) 位得到它们与 \(y\) 的关系,从而在询问的时候直接输出答案即可。
考虑更快优化,因为 \(\frac xy =n\),且 \(2\leq n \leq 79\),\(x\) 又是固定 \(5\) 位数,所以我们可以直接枚举 \(10234\sim98765\),然后除去 \(n\) 得到 \(y\),最后只要检查 \(x\) 与 \(y\) 是否满足排列的关系即可。
(全排列预处理)代码
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
struct Node {
int x, y;
} ans[80][100000];
int cnt[100];
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int a[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
do {
int x = 0, y = 0;
for (int i = 0; i < 5; i ++) {
x = x * 10 + a[i];
y = y * 10 + a[i + 5];
}
if (x % y == 0 && x / y <= 79) {
int d = x / y;
cnt[d] ++;
ans[d][cnt[d]].x = x;
ans[d][cnt[d]].y = y;
}
} while (next_permutation(a, a + 10));
int n, f = 0;
while (scanf("%d", &n)) {
if (n == 0) {
break;
}
if (f == 1) printf("\n");
f = 1;
if (cnt[n] == 0) {
printf("There are no solutions for %d.\n", n);
} else {
for (int i = 1; i <= cnt[n]; i ++) {
printf("%05d / %05d = %d\n", ans[n][i].x, ans[n][i].y, n);
}
}
}
return 0;
}
(枚举优化)代码
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, F = 0;
while (scanf("%d", &n)) {
if (n == 0) {
break;
}
if (F == 1) printf("\n");
F = 1;
int cnt = 0;
for (int x = 10234; x <= 98765; x ++) {
if (x % n == 0) {
int y = x / n;
int num[10] {};
for (int i = 1; i <= 10000; i *= 10) {
num[x / i % 10] ++;
num[y / i % 10] ++;
}
int ok = 1;
for (int i = 0; i <= 9; i ++) {
if (num[i] == 0) {
ok = 0;
}
}
if (ok == 0) {
continue;
}
cnt ++;
printf("%05d / %05d = %d\n", x, y, n);
}
}
if (cnt == 0) {
printf("There are no solutions for %d.\n", n);
}
}
return 0;
}
(优化预处理)代码
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
struct Node {
int x, y;
} ans[80][100000];
int cnt[100];
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
for (int x = 10234; x <= 98765; x ++) {
for (int n = 2; n <= 79; n ++) {
if (x % n == 0) {
int y = x / n;
int num[10] {};
for (int i = 1; i <= 10000; i *= 10) {
num[x / i % 10] ++;
num[y / i % 10] ++;
}
int ok = 1;
for (int i = 0; i <= 9; i ++) {
if (num[i] == 0) {
ok = 0;
}
}
if (ok == 0) {
continue;
}
cnt[n] ++;
ans[n][cnt[n]].x = x;
ans[n][cnt[n]].y = y;
}
}
}
int n, f = 0;
while (scanf("%d", &n)) {
if (n == 0) {
break;
}
if (f == 1) printf("\n");
f = 1;
if (cnt[n] == 0) {
printf("There are no solutions for %d.\n", n);
} else {
for (int i = 1; i <= cnt[n]; i ++) {
printf("%05d / %05d = %d\n", ans[n][i].x, ans[n][i].y, n);
}
}
}
return 0;
}
最大乘积 Maximum Product
思路
枚举区间起点和终点,计算区间乘积,取最大值即可,注意答案可能会超过 int 范围,需用 long long。
代码
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
constexpr int N = 20;
i64 a[N];
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, cnt = 0;
while (cin >> n) {
for (int i = 1; i <= n; i ++) {
cin >> a[i];
}
i64 ans = 0;
for (int l = 1; l <= n; l ++) {
for (int r = l; r <= n; r++) {
i64 res = 1;
for (int k = l; k <= r; k++) {
res *= a[k];
}
ans = max(ans, res);
}
}
cout << "Case #" << ++cnt << ": The maximum product is " << ans << ".\n\n";
}
return 0;
}
分数拆分 Fractions Again?!
思路
由题目得 \(x,y\) 是正整数,有 \(x>0,y>0\)。
\[\because x\ge y \]\[\therefore \frac 1x \le \frac 1y,且 \frac 1x = \frac 1k -\frac 1y =\frac{y-k}{ky} \]\[\therefore \frac 1k - \frac 1y\le \frac 1y,y\le 2k,y>k \]所以我们可以从 \(k+1\sim2k\) 枚举 \(y\),然后算出 \(x\),记录答案即可。
代码
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
constexpr int N = 20010;
int x[N], y[N];
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int k;
while (cin >> k) {
int cnt = 0;
for (int i = k + 1; i <= 2 * k; i ++) {
if (i * k % (i - k) == 0) {
cnt ++;
y[cnt] = i, x[cnt] = i * k / (i - k);
}
}
cout << cnt << '\n';
for (int i = 1; i <= cnt; i++) {
cout << "1/" << k << " = 1/" << x[i] << " + 1/" << y[i] << '\n';
}
}
return 0;
}
P2141 [NOIP2014 普及组] 珠心算测验
思路
要求找到 \(x+y=z[x,y,z\in A]\),因为数据很小,那么我们可以直接三次循环枚举 \(z,y,z\) 然后判断加数和被加数是否不相同,并且它们的和等于 \(z\),注意,题目问的是集合 \(A\) 中有多少个数等于集合中另外两个不同的数的和,也就是说 \(2+4=6\) 和 \(1+5=6\) 这种只能算 \(1\) 次,所以我们可以另外用数组来判断 \(z\) 是否出现过,最后再循环一次,把出现过的数统计一下即可。
代码
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
const int N = 110;
int a[N], ok[N * N];
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
cin >> n;
for (int i = 1; i <= n; i ++) {
cin >> a[i];
}
for (int k = 1; k <= n; k ++) {
for (int i = 1; i <= n; i ++) {
for (int j = i + 1; j <= n; j ++) {
if (a[i] != a[j] && a[i] + a[j] == a[k]) {
ok[a[k]] = 1;
}
}
}
}
int ans = 0;
for (int i = 1; i <= N * N; i++) {
if (ok[i] != 0) {
ans ++;
}
}
cout << ans << '\n';
return 0;
}
P8772 [蓝桥杯 2022 省 A] 求和
思路
\[S=a_{1} \cdot a_{2}+a_{1} \cdot a_{3}+\cdots+a_{1} \cdot a_{n}+a_{2} \cdot a_{3}+\cdots+a_{n-2} \cdot a_{n-1}+a_{n-2} \cdot a_{n}+a_{n-1} \cdot a_{n} \]根据这个式子,你当然可以暴力的双循环进行求和,但是提交你会发现 TLE,因为题目说了对于 \(100\%\) 的数据,\(1\le n\le 2\times 10^5\),所以这个时候去双层循环显然计算机就承担不起 \(2\times 10^5 \times 2\times 10^5\) 的这样运算,因此我们需要优化。
仔细观察这个式子,其实我们可以尝试提取一下公因项,那么就可以得到:
\[S=a_1\cdot (a_2+a_3+\dots+a_n)+a_2\cdot (a_3+a_4+\dots+a_n)+\dots+a_{n-2}\cdot (a_{n-1}+a_n)+a_{n-1} \cdot a_n \]诶!是不是有点规律了?
假如我们优先把 \(a_1+a_2+a_3+\dots+a_n=sum\) 计算出来,那我们每次循环的时候减去 \(a_i\),那是不是就得到了 \(a_{i+1}+a_{i+2}+\dots+a_n\) 呢?
所以上述式子可以转变为:
\[S=\sum\limits_{i=1}^na_i\cdot(sum-\sum\limits_{j=1}^ia_j) \]同理,另外一种方法,我们给它补上缺的 \(a_1+a_2+\dots+a_i\),那最后就得到了
\[(a_1+a_2+\dots+a_n)\cdot sum-a_1\cdot a_1-a_2\cdot(a_1+a_2)-\dots-a_n\cdot(a_1+a_2+\dots+a_n) \]即:
\[S=sum^2-\sum\limits_{i=1}^na_i\cdot(\sum\limits_{j=1}^ia_j) \]不过最后这个方法感兴趣的同学可以自己写写,这里就只放第一种了。
代码
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
const int N = 200100;
int a[N];
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
cin >> n;
long long sum = 0;
for (int i = 1; i <= n; i ++) {
cin >> a[i];
sum += a[i];
}
long long ans = 0;
for (int i = 1; i <= n; i ++) {
sum -= a[i];
ans += sum * a[i];
}
cout << ans << '\n';
return 0;
}
P1618 三连击(升级版)
思路
看到要求 \(1\sim9\) 的方案数,那自然想到一种暴力是全排列了,用上next_permutation
这个函数,可以很快求得排列方案,需要注意这个函数最初的数列,必须要从最小到从大排列,所以一般会搭配sort
使用,不过我们这里直接初始化了,就不用排序,然后就是根据比例关系 \(\frac ab=\frac xy\to a\times y=b\times x\) 判断是否合法,其他比例同理。
当然,和前面的那道题一样,我们也枚举三位数,然后根据比例计算出其他两个数,判断是否是 \(1\sim9\) 的排列即可。
(全排列)代码
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
long long a, b, c;
cin >> a >> b >> c;
int A[9] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
int f = 0;
do {
int x = 0, y = 0, z = 0;
for (int i = 0; i < 3; i ++) {
x = x * 10 + A[i];
y = y * 10 + A[i + 3];
z = z * 10 + A[i + 6];
}
if (b * x == a * y && b * z == c * y && a * z == c * x) {
f = 1;
cout << x << ' ' << y << ' ' << z << '\n';
}
} while (next_permutation(A, A + 9));
if(f == 0){
cout << "No!!!\n";
}
return 0;
}
(枚举三位数)代码
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int a, b, c;
cin >> a >> b >> c;
if (a == 0) {
cout << "No!!!\n";
return 0;
}
bool f = false;
for (int i = 123; i <= 329; i++) {
int x = i, y = i * b / a, z = i * c / a;
if (y < 100 || y > 1000 || z < 100 || z > 1000)continue;
int vv[10] {};
vv[x / 100] = vv[x / 10 % 10] = vv[x % 10] = 1;
vv[y / 100] = vv[y / 10 % 10] = vv[y % 10] = 1;
vv[z / 100] = vv[z / 10 % 10] = vv[z % 10] = 1;
if (vv[1] && vv[2] && vv[3] && vv[4] && vv[5] && vv[6] && vv[7] && vv[8] && vv[9]) {
cout << x << " " << y << " " << z << '\n';
f = true;
}
}
if (f == false) {
cout << "No!!!" << '\n';
}
return 0;
}
B3968 [GESP202403 五级] 成绩排序
思路
此题考察自定义排序,强烈要求同学们好好写。
此外题中要求要按同学原来的顺序输出他们各自的排名,所以我们在按要求排完序后还得记录他们各自的排名,然后再按照他们原来的顺序再排序回去。
代码
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
constexpr int N = 10010;
struct Node {
int c, m, e;
int id, rank;
} a[N];
bool cmp(Node x, Node y) {
if (x.c + x.m + x.e != y.c + y.m + y.e) {
return x.c + x.m + x.e > y.c + y.m + y.e;
}
if (x.c + x.m != y.c + y.m) {
return x.c + x.m > y.c + y.m;
}
if (max(x.c, x.m) != max(y.c, y.m)) {
return max(x.c, x.m) > max(y.c, y.m);
}
return 1;
}
//根据id还原原来的顺序
bool cmp1(Node x, Node y) {
return x.id < y.id;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
cin >> n;
for (int i = 1; i <= n; i ++) {
cin >> a[i].c >> a[i].m >> a[i].e;
a[i].id = i;
}
sort(a + 1, a + 1 + n, cmp);
a[1].rank = 1;
for (int i = 2; i <= n; i ++) {
a[i].rank = i;
if (a[i].c + a[i].m + a[i].e == a[i - 1].c + a[i - 1].m + a[i - 1].e) {
if (a[i].c + a[i].m == a[i - 1].c + a[i - 1].m) {
if (max(a[i].c, a[i].m) == max(a[i - 1].c, a[i - 1].m))
a[i].rank = a[i - 1].rank;
}
}
}
sort(a + 1, a + 1 + n, cmp1);
for (int i = 1; i <= n; i ++) {
cout << a[i].rank << '\n';
}
return 0;
}
P1177 【模板】排序
思路
考察排序的用法。
代码
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
constexpr int N = 100010;
int a[N];
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
cin >> n;
for (int i = 1; i <= n; i ++) {
cin >> a[i];
}
sort(a + 1, a + 1 + n);
for (int i = 1; i <= n; i ++) {
cout << a[i] << ' ';
}
cout << '\n';
return 0;
}
P2676 [USACO07DEC] Bookshelf B
思路
要求我们用最少的奶牛叠到一定高度,就和用最少的钱凑成一定的数一样,贪心的选取最大的来凑,从大到小排序后,当某一个数凑起来大于了给定的数之后,输出这个数的位置即可。
代码
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
constexpr int N = 100010;
int a[N];
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, w;
cin >> n >> w;
for (int i = 1; i <= n; i ++) {
cin >> a[i];
}
sort(a + 1, a + 1 + n, greater<>());
int sum = 0;
for (int i = 1; i <= n; i ++) {
if (sum + a[i] < w) {
sum += a[i];
} else {
cout << i << '\n';
break;
}
}
return 0;
}
P1478 陶陶摘苹果(升级版)
思路
和上面那道题类似,只不过这题问的是 \(s<0\) 之前最多能摘到多少苹果,所以当 \(s-A_i<0\) 的时候我们得输出 \(i-1\) 也就是最多只能摘 \(i-1\) 个苹果;
另外,题目要求 \(h_i\le a+b\) 的才可以摘,这种有个小技巧就是我们在输入的时候只把符合要求的记录下来,大于 \(a+b\) 的我们不记录即可,还有可能所有的苹果摘完了还没耗尽力气,这个直接输出我们能摘到的最多苹果数即可。
代码
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
constexpr int N = 100010;
int A[N];
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, s, a, b;
cin >> n >> s >> a >> b;
int cnt = 0;
for (int i = 1; i <= n; i ++) {
int x, y;
cin >> x >> y;
if (x <= a + b) {
cnt ++;
A[cnt] = y;
}
}
sort(A + 1, A + 1 + cnt);
for (int i = 1; i <= cnt; i ++) {
if (s >= A[i]) {
s -= A[i];
} else {
cout << i - 1 << '\n';
return 0;
}
}
cout << cnt << '\n';
return 0;
}
P1223 排队接水
思路
要使得整体的平均等待时间最短,那么只能让打水快的人先打,这样后面的人才能排队时间更短,否则让一个打得很慢的人排在前面,那么后面\(n-1\) 个人都得等他打完。
cout<<fixed<<setprecision(x)<<
是c++保留几位小数的函数,要保留几位,\(x\) 就填几,记不住也可以用C语言的 printf("%.2lf",ans),不过要记住,c++的输入输出语法最好不要和C语言混用,要用printf,那么输入尽量也换成scanf。
代码
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
constexpr int N = 100010;
struct Node {
int time, id;
} a[N];
bool cmp(Node x, Node y) {
return x.time < y.time;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
cin >> n;
for (int i = 1; i <= n; i ++) {
cin >> a[i].time;
a[i].id = i;
}
sort(a + 1, a + 1 + n, cmp);
double ans = 0, now = 0;
for (int i = 1; i <= n; i ++) {
cout << a[i].id << " ";
ans += now;
now += a[i].time;
}
ans /= n;
cout << '\n';
cout << fixed << setprecision(2) << ans << '\n';
return 0;
}
标签:10,int,cin,long,枚举,vv,using,排序,贪心
From: https://www.cnblogs.com/Kescholar/p/18464250