校运会新项目
先按照时间排序,相同时间排名相同,按照排名从高到低排序,相同排名按照字典序排序
具体可以看代码是如何实现的
#include <stdio.h>
#include <string.h>
struct Student {
char name[21];
int m, s;
} stu[10], swap;
int main() {
int t;
scanf("%d", &t);
for (int i = 1; i <= t; i++) {
int n;
scanf("%d", &n);
for (int j = 0; j < n; j++) {
scanf("%s %d:%d", stu[j].name, &stu[j].m, &stu[j].s);
}
for (int j = 0; j < n - 1; j++) {//冒泡排序
for (int k = 0; k < n - 1 - j; k++) {
if ((stu[k].m > stu[k + 1].m) || (stu[k].m == stu[k + 1].m && stu[k].s > stu[k + 1].s) ||
(stu[k].m == stu[k + 1].m && stu[k].s == stu[k + 1].s &&
strcmp(stu[k].name, stu[k + 1].name) > 0)) {
swap = stu[k];
stu[k] = stu[k + 1];
stu[k + 1] = swap;
}
}
}
int u = 1;
printf("Case #%d:\n", i);
printf("%s %d\n", stu[0].name, u);
for (int j = 1; j < n; j++) {
if (stu[j].m != stu[j - 1].m || stu[j].s != stu[j - 1].s)//排名
u++;
printf("%s %d\n", stu[j].name, u);
}
}
return 0;
}
小蚂蚁找位置
依据题意返回数组下标即可,代码实现可以看下面
#include<stdio.h>
int searchInsert(int *a, int n, int target) {
for (int i = 0; i < n; i++) {
if (a[i] >= target)
return i;
}
return n;
}
int main() {
int T;
while (~scanf("%d", &T)) {
int a[2000], n, target;
for (int T1 = 1; T1 <= T; T1++) {
scanf("%d", &n);
for (int i = 0; i < n; i++) {
scanf("%d", &a[i]);
}
scanf("%d", &target);
printf("Case #%d:\n%d\n", T1, searchInsert(a, n, target));
}
}
}
简单的飞行棋
如果某一个作为起跳点的格子可以跳跃的距离是4,那么表示后面4个格子都可以作为起跳点。
可以对每一个能作为起跳点的格子都尝试跳一次,把能跳到最远的距离不断更新。
如果可以一直跳到最后,就成功了。
#include<stdio.h>
int max(int a, int b) {
if (a > b)
b = a;
return b;
}
int main() {
int n, a[1000];
int m;
while (~scanf("%d", &m)) {
int ans = 1;
while (m--) {
int m1 = 0;
int max1 = 0;
scanf("%d", &n);
for (int i = 0; i < n; i++) {
scanf("%d", &a[i]);
}
printf("Case #%d:\n", ans++);
for (int i = 0; i < n; i++) {
if (i <= max1) {
max1 = max(max1, i + a[i]);//i指位置,a[i]指可以跳到的位置
if (i >= n - 1 && m1 != 1) {
printf("true\n");
m1 = 1;
break;
}
}
}
if (m1 == 0) {
printf("false\n");
}
}
}
}
宿舍内战
由规律可知每次当数字为偶数的时候lmm必胜
可以自行多举例子,由规律可知每次当数字为偶数的时候lmm必胜
M=1 的时候,区间 (0, 1) 中没有整数是 n 的因数,所以此时 LMM 败。
M= 2 的时候,LMM 只能拿 1,M 变成 1,ZMM 无法继续操作,故 LMM 胜。
M = 3 的时候,LMM 只能拿 1,M 变成 2,根据 M=2 的结论,我们知道此时 ZMM 会获胜,LMM 败。
M = 4 的时候,LMM 能拿 1 或 2,如果 LMM 拿 1,根据 M=3 的结论,ZMM 会失败,LMM 会获胜。
M = 5 的时候,LMM 只能拿 1,根据 M=4 的结论,LMM 会失败。
#include<stdio.h>
int main() {
int m, n, t;
while (~scanf("%d", &t)) {
int ans = 1;
while (t--) {
scanf("%d", &m);
printf("Case #%d:\n", ans++);
if (m % 2 == 0)
printf("true\n");
else
printf("false\n");
}
}
}
后海有树的院子
暴力时间会超限
而且,最后的结果超出了int的范围,需要使用long long
需要使用前缀和的预处理方式
一维前缀和代码
#include<stdio.h>
#include<string.h>
#define ll long long
ll cb[2001][2001];
int main() {
ll t;
memset(cb, 0, sizeof(cb));
scanf("%lld", &t);
ll l, w;
scanf("%lld %lld", &l, &w);
ll kk;
for (ll i = 1; i <= l; i++)
for (ll j = 1; j <= w; j++) {
scanf("%lld", &kk);
cb[i][j] = kk + cb[i][j - 1];
}
for (int i = 1; i <= t; i++) {
ll n, m;
ll ans = 0;
scanf("%lld %lld", &n, &m);
for (ll j = 1; j <= n; j++) {
ans += cb[j][m];
}
printf("Case #%lld:\n%lld\n", i, ans);
}
}
买比特币的最佳时机
暴力也能过,没卡时间
暴力代码:
#include<stdio.h>
int main() {
int t, s = 1;
scanf("%d", &t);
while (t--) {
int i, j;
printf("Case #%d:\n", s++);
int all[40];
int n;
int num = 0;
scanf("%d", &n);
for (i = 0; i < n; i++) {
scanf("%d", &all[i]);
}
for (i = 0; i < n; i++) {
for (j = i; j < n; j++) {
int k = all[j] - all[i];
if (k > num) {
num = k;
}
}
}
printf("%d\n", num);
}
}
可以看看下面dp的写法
dp四部曲:
1.确定状态 :状态就是前i天的最大收益;
2.转移方程 :前i天的最大收益 = max{前i-1天的最大收益,第i天的价格-前i-1天中的最小价格};
3.初始条件和边界条件 :把min设置成第一天的价格,让利润b=0;
4.计算顺序 :从头到尾,从第二天(数组下标为1)开始计算。
#include<stdio.h>
int max(int a, int b) {
return a > b ? a : b;
}
int main() {
int n, T;
while (~scanf("%d", &T)) {
for (int T1 = 1; T1 <= T; T1++) {
scanf("%d", &n);
int prices[100];
for (int i = 0; i < n; i++)
scanf("%d", &prices[i]);
int min = prices[0];
int b = 0;
for (int i = 1; i < n; i++) {
if (prices[i] < min) {
min = prices[i];
}
if (i == 1) {
prices[i] = max(0, prices[i] - min);
} else {
prices[i] = max(prices[i - 1], prices[i] - min);
}
}
printf("Case #%d:\n%d\n", T1, prices[n - 1]);
}
}
return 0;
}
诗句里选取的意义
两个字母交换
注意的是,下标从1开始
而且给出的是启焦的操作,我们如果复原需要倒序进行操作
#include<stdio.h>
int main() {
int t, a[101], b[101], k;
char str[1190];
scanf("%d", &t);
for (int q = 1; q <= t; q++) {
getchar();
gets(str + 1);
scanf("%d", &k);
for (int l = 1; l <= k; l++) {
scanf("%d %d", &a[l], &b[l]);
}
for (int l = k; l >= 1; l--) {
if (str[a[l]] != str[b[l]])
str[a[l]] ^= str[b[l]] ^= str[a[l]] ^= str[b[l]];
}
printf("Case #%d:\n", q);
puts(str + 1);
}
}
逃出剑剑的魔爪
我们可以先考虑总共有多少道排列方式, 由于n个格子,每个位置有m种仓鼠物种,所以根据乘法原理,一共有m^n 种取法。
然后我们再考虑不会逃出盒子的情况,这样我们只要保证当前这一个与前面一个不同就可以了,所以不会逃出盒子的情况有m* (m-1)^(n-1)种取法。
所以很容易得到答案就是m^n - m* (m-1)^(n-1),但是普通的算法会爆时间,要用快速幂
#include<stdio.h>
#define MOD 100003
#define ll long long
ll mod_pow(ll x, ll n) //求x的n次方
{
ll ans = 1;
while (n) {
if (n & 1) ans = (ans * x) % MOD; //判断n是否为奇数,奇数乘上x
x = (x * x) % MOD; //将x平方
n >>= 1; //将n除以2
}
return ans;
}
int main() {
int t;
while (~scanf("%d", &t)) {
ll m, n, ans;
int j = 0;
for (int i = 0; i < t; i++) {
scanf("%lld %lld", &m, &n);
ans = (mod_pow(m, n) - (m * mod_pow(m - 1, n - 1)) % MOD) % MOD;
if (ans < 0) ans += MOD;
j++;
printf("Case #%d:\n%lld\n", j, ans);
}
}
return 0;
}
010和101
注意:子序列的概念
题目大意
给你只有0和1组成的字符串,你每次操作可以将某一位上的0翻转成1,1翻转成0。求最少反转多少次才能使得字符串中没有“101”或者“010”
分析
为了让字符串中不包括子序列“010”或“101”,那么我们修改后的字符串只有3种可能:全是0,全是1,一边是0一边是1(如0001111)这三种情况
一边是0一边是1的情况会有一个分割线,例如000|111这里就是有一个0和1的分割线,如果全为0或者1,就是分割线在最左边或者最右边的情况
因此,我们可以枚举这个分割线的所有位置,并计算出分割线在该位置时需要的最小修改次数,最后找出最小的修改次数即可。
#include <stdio.h>
#include <string.h>
int min(int a, int b);
int main() {
int t;
scanf("%d", &t);
for (int i = 1; i <= t; ++i) {
char s[1000];
scanf("%s", s);
int cnt0 = 0, cnt1 = 0;
//表示分割线的右边的0/1数量
//因为一开始分割线位于字符串的最左边(|00010010)
for (int j = 0; j < (strlen(s)); j++) {
//所以一开始cnt存的是整个字符串中0/1的数量
if (s[j] == '0') cnt0++;
else cnt1++;
}
int k0 = 0, k1 = 0;
//表示分割线左边0/1的数量(一开始都是0)
int ans = min(cnt0, cnt1);
//记录答案(全局最小修改次数)
for (int j = 0; j < strlen(s); j++)
{
//枚举分割线的位置
if (s[j] == '0'){
k0++, cnt0--;
}
//分割线右移,cnt和k相应的增减
else {
k1++, cnt1--;
}
ans = min(ans, min(k0, k1) + min(cnt0, cnt1));
//更新最小值
}
printf("Case #%d:\n%d\n", i, ans);
}
return 0;
}
int min(int a, int b) {
return a < b ? a : b;
}
乌鸦和写字台
题意:
给出凸多边形的每一个角的坐标,求出任意三点围成的三角形面积的最小值
思路:
我们可以确定,相邻的三个点组成的三角形才有可能是最短的,然后遍历一遍就行
#include<stdio.h>
#include<math.h>
double x[10000];
double y[10000];
double area[10000];
double getArea(double x1, double y1, double x2, double y2, double x3, double y3) {//求面积
double a, b, c;
a = sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
b = sqrt((x1 - x3) * (x1 - x3) + (y1 - y3) * (y1 - y3));
c = sqrt((x2 - x3) * (x2 - x3) + (y2 - y3) * (y2 - y3));
double p = (a + b + c) / 2;
double ans = sqrt(p * (p - a) * (p - b) * (p - c));
return ans;
}
int main() {
int t;
scanf("%d", &t);
for (int q = 1; q <= t; q++) {
int n;
scanf("%d", &n);
for (int j = 1; j <= n; j++) {
scanf("%lf %lf", &x[j], &y[j]);
}
x[0] = x[n], y[0] = y[n];
for (int i = 1; i < n; i++) {//统计每个三角形的面积
area[i] = getArea(x[i], y[i], x[i - 1], y[i - 1], x[i + 1], y[i + 1]);
}
area[n] = getArea(x[n], y[n], x[n - 1], y[n - 1], x[1], y[1]);
double min = 1e5;
for (int i = 1; i <= n; i++) {//求最小
if (min > area[i]) {
min = area[i];
}
}
printf("Case #%d:\n%.2lf\n", q, min);
}
}