A.中奖
思路
对于Java的话是写一个类,c++是写一个结构体,
或者你写个二维数组,然后排序,重写一下排序函数即可
我是按照从小到大排序,然后倒着输出的
这样的就是,
1.金额小的在前面
2.金额相同,小时大的在前面
3.小时也相同,分钟大的在前面
重写cmp函数
/**
* @author Changersh
* @date 2022/7/16 14:01
*/
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int m = scanner.nextInt();
int[][] s = new int[n][3];
for (int i = 0; i < n; i++) {
s[i][0] = scanner.nextInt();
s[i][1] = scanner.nextInt();
s[i][2] = scanner.nextInt();
}
Arrays.sort(s, new Comparator<int[]>() {
@Override
public int compare(int[] o1, int[] o2) {
if (o1[2] != o2[2]) {
return o1[2] - o2[2];
}
else if (o1[0] != o2[0]) {
return -(o1[0] - o2[0]);
}
else {
return -(o1[1] - o2[1]);
}
}
});
for (int i = n - 1; m > 0; i--) {
System.out.println(s[i][0] + " " + s[i][1] + " " + s[i][2]);
m--;
}
}
}
B.构造一个简单的序列
思路
需要注意到的是,这一题java给了 10s的运行时间,所以就是支持我们暴力?
题意是 让构造数列
给你 a n
1.数列第一项必须是 a,求第n项
2.相邻两个数互质
3.不能有重复的数字
4.优先选满足的小的数字
如何判断两个数是否互质?
1.相邻的两个数必然互质
2.gcd = 1 互质
所以用 gcd来判断就行
思路是,先定义一个标记数组,判断当前数是否已经使用过了
然后 idx 是当前到哪个数字了,pre记录上个满足条件的数字,即与当前要判断的相邻的数字
把 a 放进去之后,for循环 n - 1 次,,即可
循环中,要先看当前的 数字是否被用过了,所以要循环判断一下,因为数字不能重复,但是pre不要更新哈,因为你现在变化的 idx 都是之前已经用过的
然后就是判断是否互质,是 就 idx++,更新pre
否 就要循环去找适合的数字,知道遇到了 和pre互质并且没有用过的数字,循环终止
这里要用 tmp 来循环,因为我们的 pre 和 idx 都是记录在外循环外面的,idx 要保持着对应一个还没有使用过的,并且它前面的数字都是已经被使用过的,相当于一个 标记指针吧 ,因为我们要尽量选择最小的数嘛
最后n - 1次循环结束之后,我们就输出pre就好
为了节省时间,我们开始的时候可以i提前特判一下,n = 1 的时候就不用循环了,直接输出 a 即可
暴力?
/**
* @author Changersh
* @date 2022/7/17 8:57
* Java运行时间 10s?直接暴力嘛
*/
import java.util.*;
public class Main {
private static byte[] vis = new byte[1000005];
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int T = scanner.nextInt();
while (T-- > 0) {
int a = scanner.nextInt();
int n = scanner.nextInt();
if (n == 1) {
System.out.println(a);
continue;
}
byte b = 0;
Arrays.fill(vis, b);
int idx = 1, pre = a;
vis[a] = 1;
for (int i = 1; i < n; i++) {
while (vis[idx] == 1) { // 这里 pre不能更新,因为只是说当前idx被用过了,但是,顺序不同啊,pre还是上个循环剩下的pre
idx++;
}
if (_gcd(pre, idx) == 1) { // 互质
// 只有真正找到互质之后才更新 pre
pre = idx;
idx++;
}
else {
int tmp = idx;
while (_gcd(pre, tmp) != 1 || vis[tmp] == 1) {
tmp++;
}
vis[tmp] = 1;
pre = tmp;
}
}
System.out.println(pre);
}
}
private static int _gcd(int a, int b) {
return b == 0 ? a : _gcd(b, a % b);
}
}
E.排列计数
思路
如下,找规律,虽然我到现在也没有找到到底 3 以及之后的要怎么算,但是看dalao题解就是找到了一个规律,最后的答案是:2n! / 2,这个需要 / 2,所以写个快速幂 求个 pow(2, mod - 2) ,即逆元,乘上去就好
还有一种规律是 1 特判是 1
从 3 开始乘就不用除了,直接阶乘就好
找规律 + 逆元?
/**
* @author Changersh
* @date 2022/7/16 22:42
* 其实就是 阶乘
*/
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
long res = 1;
long mod = 1000000000 + 7;
for (int i = 3; i <= 2 * n; i++) {
res = res * i % mod;
}
System.out.println(res % mod);
}
}
G.登山小分队
思路
我真的看不懂,先放在这里,等我学学dfs再写
dfs暴力
/*keep on going and never give up*/
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define ll long long
#define db(x) cerr<<(#x)<<" "<<(x)<<" "<<endl;
#define endl "\n"
#define INF 1e17
#define fast std::ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
const double E = exp(1);
const double PI = acos(-1.0);
const int maxn=1e3+10;
vector<int>q[maxn];
int num[maxn],ans;
void dfs(int u,int f){
for(int i=0;i<q[u].size();i++){
int v=q[u][i];
if(v==f) continue;
if(num[v]){
num[u]++;
num[v]--;
}
dfs(v,u);
}
}
signed main(){
int n,u,v;
cin>>n;
for(int i=1;i<n;i++){
cin>>u>>v;
q[u].push_back(v);
q[v].push_back(u);
}
for(int i=1;i<=n;i++){
if(q[i].size()==1){
ans++;
num[i]=1;
}
}
int res=0;
while(num[1]!=ans){
res++;
dfs(1,1);
}
cout<<res<<endl;
}
H.拼接的字符串
思路
题意是给两个字符串,判断 第一个字符串 是不是 第二个字符串 的前缀或者后缀
首尾遍历一下有多少个匹配的,加起来看是否大于 第一个字符串的长度
纯套函数
/**
* @author Changersh
* @date 2022/7/16 14:24
*/
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
char[] a = scanner.next().toCharArray();
char[] b = scanner.next().toCharArray();
int aLen = a.length, bLen = b.length;
int ans = 0;
for (int i = 0; i < aLen && i < bLen; i++) {
if (a[i] != b[i]) {
break;
}
ans++;
}
int minL = Math.min(aLen, bLen);
for (int i = minL - 1; i >= 0; i--) {
if (a[i] != b[i]) {
break;
}
ans++;
}
System.out.println(ans >= aLen ? "YES" : "NO");
}
}
// 纯捡漏好吧,这个代码其实是错的,可能正好卡到数据才对的
//public class Main {
// public static void main(String[] args) {
// Scanner scanner = new Scanner(System.in);
// String a = scanner.next();
// String b = scanner.next();
// if (a.length() > b.length() || a == null) {
// System.out.println("YES");
// }
// else {
// String c = b.substring(0, a.length());
// String d = b.substring(b.length() - a.length());
// if (c.equals(a) || d.equals(a))
// System.out.println("YES");
// else
// System.out.println("NO");
// }
// }
//}
I.没有字母的数
思路
刚开始我想的是只要取一次模 < 10 就行了,太笨了
因该是只能一直取模到除完,每次都要判断一下才行
时间是 java 4s,就是让暴力的,但是有 200000组样例,每一组最多 1e6,真的每次都暴力肯定会超
所以直接对 1e6预处理,然后求前缀和,之后直接输出前缀的差值就可以了
预处理 + 暴力
/**
* @author Changersh
* @date 2022/7/16 14:36
* 预处理很重要!!!
*/
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// 预处理!!!
int maxN = 1000005;
int[] pre = new int[maxN];
pre[0] = 0;
for (int i = 1; i < maxN; i++) {
int x = i;
pre[i] = 1;
while (x > 0) {
if (x % 16 > 9) {
pre[i] = 0;
break;
}
x /= 16;
}
}
for (int i = 1; i < maxN; i++) {
pre[i] += pre[i - 1];
}
int T = scanner.nextInt();
while (T-- > 0) {
int l = scanner.nextInt();
int r = scanner.nextInt();
int ans = pre[r] - pre[l - 1];
System.out.println(ans);
}
}
}