九韶杯-题解(Java)
Posted nuist__NJUPT
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了九韶杯-题解(Java)相关的知识,希望对你有一定的参考价值。
目录
A题:6的个数
答案:602
思路:枚举+计数就可以。
public class Main
public static void main(String[] args)
long ans = 0 ;
for(int i=1; i<=2021; i++)
String s = String.valueOf(i) ;
for(int j=0; j<s.length(); j++)
if(s.charAt(j)=='6')
ans ++ ;
System.out.println(ans);
B题:小明的作业
答案:78 25
思路:枚举所有情况,累计错误和警告数量即可。
public class Main
public static void main(String[] args)
String homework = "iawaswapwauawhawdwafwanbiopwanivgbik" +
"vblvbwawawawvolyuvgbololvolgbyolgyowagbolg" +
"awgboplwawaolgyolwaogblwaygbowawagwabwayawopwawa" +
"gyowabwaowapjwapcfrtuywawacvujwawawaufttyfuftywawawatifgugbgby" +
"guwawawawayugbigwwwytigwygwgbwyoawawgoghwaogwborgrewabouyhwabyu" +
"howabhnwawauygbawyawuwaoawfcawaaaahwaywauwagwawefwaafmbawklawjiawi" +
"hnwanhawawawawijwajiofjeriofgjrefjhwaewarwaowagwahwauwaiwarwaiwaq" +
"warwahwaqwawwaowapfweofbwewafwahwaiwaewawwawawawawafwawawawaeiufw" +
"epfhnewfwahwajwatwafowawajtokshwawafwaiwahwafwahmgoewawawawafkfjke" +
"wnwawafiewhfwawawafjkernhawkrenwawawawafujnrheiowanwakawawawawwan" +
"oifewajrwaoawawfweojnwawawawawawawafjkwenawawferkwmpwawawawaforeijaw" +
"awferhfiueorghwuwafguwegfwaghrwiufgwahweofgowaidwiweaiwwawieyiwe" ;
long warn = 0, error = 0 ;
for(int i=0; i<homework.length()-1; i++)
if(homework.charAt(i) == 'w' && homework.charAt(i+1)=='a' && homework.charAt(i+2) != 'w')
warn ++ ;
i ++ ;
if(homework.charAt(i) == 'a' && homework.charAt(i+1)=='w' && homework.charAt(i+2) != 'a')
warn ++ ;
i++ ;
if(homework.charAt(i)=='w' && homework.charAt(i+1)=='a' && homework.charAt(i+2)=='w' && homework.charAt(i+3)=='a')
error ++ ;
i += 4 ;
while(homework.charAt(i)=='w' && homework.charAt(i+1)=='a')
i += 2 ;
i-- ;
if(homework.charAt(i)=='a' && homework.charAt(i+1)=='w' && homework.charAt(i+2)=='a' && homework.charAt(i+3)=='w')
error ++ ;
i += 4 ;
while(homework.charAt(i)=='a' && homework.charAt(i+1)=='w')
i += 2 ;
i--;
System.out.println(warn);
System.out.println(error);
C题:斐波那契
答案:6535086616739/3684083162760
思路:这题对Java来说,最需要注意的是要用long,int会爆,本题说白了就是求最大公约数和最小公倍数的问题。
public class Main
static long [] f ;
static long [] ans ;
public static void main(String[] args)
f = new long [14] ;
ans = new long [14] ;
f[0] = f[1] = 1 ;
ans[1] = 1 ;
for(int i=2; i<14; i++)
f[i] = f[i-1] + f[i-2] ;
ans[i] = f[i-1] * f[i] ;
long fenMu = 1 ;
for(int i=1; i<14; i++)
fenMu = lcd(fenMu,ans[i]) ;
long fenZi = 0 ;
for(int i=1; i<14; i++)
fenZi += (fenMu / ans[i]) ;
System.out.println(fenZi/gcd(fenMu,fenZi) + "/" + fenMu/gcd(fenMu, fenZi));
private static long lcd(long m, long n)
return m * n / gcd(m, n) ;
private static long gcd(long m, long n)
if(n==0)
return m ;
else
return gcd(n, m%n) ;
D题:数列重组
答案:21456
思路:全排列问题的变种,求全排列,对于每个排列需要找出小于等于两次升降变化的,就是满足要求的,不过本题的数字有重复的,就是可能出现重复的全排列,一般使用抓取法,提前去重,也可以使用交换法全排列之后,再用set集合去重。
抓取法全列代码如下:
import java.util.Arrays;
public class Main
static int [] arr = 2,5,3,6,3,6,7,3,7,8 ;
static long ans = 0 ;
static boolean [] vis = new boolean [10] ;
static int [] path = new int [10] ;
public static void main(String[] args)
Arrays.sort(arr) ;
full(0) ;
System.out.println(ans);
private static void full(int k)
if(k==10)
//升降的变化不得大于2次,否则分不成三个满足要求的
int num = 0;
boolean up = false, down = false;
for (int j = 0; j < 9; j++)
if (path[j] < path[j + 1])
up = true;
else if (path[j] > path[j + 1])
down = true;
if(up && down)
num++;
up = false;
down = false ;
if (num <= 2)
ans++;
for(int i=0; i<10; i++)
if((i>0 && arr[i] == arr[i-1] && !vis[i-1]))
continue ;
if(!vis[i])
vis[i] = true;
path[k] = arr[i];
full(k + 1);
vis[i] = false;
交换法全排列,set集合去重代码如下,这个也是正确的,不过超时了,其实填空题运行出结果就可以了。
import java.util.Set;
import java.util.TreeSet;
public class Main
static int [] arr = new int [] 2,5,3,6,3,6,7,3,7,8 ;
static long ans = 0 ;
static Set<String> set = new TreeSet<>() ;
public static void main(String[] args)
//全排列
full(0) ;
System.out.println(ans);
private static void full(int k)
if(k==10)
int size = set.size() ;
String s = "" ;
for(int element : arr)
s += element ;
set.add(s) ;
if(set.size() == size + 1)
//升降的变化不得大于2次,否则分不成三个满足要求的
int num = 0;
boolean up = false, down = false;
for (int j = 0; j < 9; j++)
if (arr[j] < arr[j + 1])
up = true;
if (down)
num++;
up = false ;
down = false;
else if (arr[j] > arr[j + 1])
down = true;
if (up)
num++;
up = false;
down = false ;
if (num <= 2)
ans++;
for(int i=k; i<10; i++)
swap(i, k) ;
full(k+1) ;
swap(i, k) ;
private static void swap(int i, int j)
int temp = arr[i] ;
arr[i] = arr[j] ;
arr[j] = temp ;
E题:三角形个数
答案:683228996
思路:找正三角形和倒三角形个数,哈哈,这题好难想,不看别人的题解,确实想不到。
public class Main
static int mod = 1000000007 ;
public static void main(String[] args)
long a = 0, n = 20210411 ;
long ans = 0 ;
for(long i=1; i<=20210411; i++)
a = (n - i + 2) * (n - i + 1) / 2 % mod ;
if((n-2*i+1)>0)
a = (a + (n - 2 * i + 1) * (n - 2 * i + 2) / 2) % mod;
ans = (ans + a) % mod;
System.out.println(ans);
F题:字符串
思路:枚举每一行的字符串,截取四个字符,判断是否是@wyk即可。
import java.util.Scanner;
public class Main
static long ans = 0 ;
public static void main(String[] args)
Scanner input = new Scanner(System.in) ;
int N = Integer.parseInt(input.nextLine()) ;
for(int i=1; i<=N; i++)
String s = input.nextLine() ;
for(int j=0; j<s.length(); j++)
if(s.charAt(j)=='@')
if (s.substring(j, j + 4).equals("@wyk"))
ans++;
break;
System.out.println(ans);
G题:最强对手矩阵
思路:这题看一下,立马想到前缀和,不过需要注意的是,小心超时问题。按行求前缀和,枚举上下行和列。AC代码如下:
import java.util.Scanner;
public class Main
static int N, M ;
static int [][] matrix ;
static int [][] matrix1 ;
static long max = Long.MIN_VALUE ;
public static void main(String[] args)
//使用前缀和记录
Scanner input = new Scanner(System.in) ;
N = input.nextInt() ;
M = input.nextInt() ;
matrix = new int [N+1][M+1] ;
for(int i=1; i<=N; i++)
for(int j=1; j<=M; j++)
matrix[i][j] = input.nextInt() ;
transpose() ;
for(int i=1; i<=N; i++)
for(int j=i; j<=N; j++)
long now = 0 ;
for(int k=1; k<=M; k++)
now = Math.max(0,now) + matrix1[j][k] - matrix1[i-1][k] ;
max = Math.max(max, now) ;
System.out.println(max);
private static void transpose()
if(N>M)
matrix1 = new int [M+1][N+1] ;
for(int i=1; i<=N; i++)
for(int j=1; j<=M; j++)
matrix1[j][i] = matrix[i][j] ;
int temp = N ;
N = M ;
M = temp ;
else
matrix1 = new int [N+1][M+1] ;
for(int i=1; i<=N; i++)
for(int j=1; j<=M; j++)
matrix1[i][j] = matrix[i][j] ;
for(int i=1; i<=N; i++)
for(int j=1; j<=M; j++) //按行求一维前缀和
matrix1[i][j] += matrix1[i-1][j] ;
第一次写出来的,是按行求出前缀和,然后枚举左上角和右下角的坐标找出最大面积,四层循环,超时了,只能拿一部分的分。代码如下:
import java.util.Scanner;
public class Main
static int N, M ;
static int [][] matrix ;
static long max = Long.MIN_VALUE ;
public static void main(String[] args)
//使用前缀和记录,枚举计算所有以(row1,col1)为左上角坐标,(row2,col2)为右下角坐标时候的矩形面积
Scanner input = new Scanner(System.in) ;
N = input.nextInt() ;
M = input.nextInt() ;
matrix = new int [N][M] ;
for(int i=0; i<N; i++)
for(int j=0; j<M; j++)
matrix[i][j] = input.nextInt() ;
for(int i=0; i<N; i++)
for(int j=1; j<M; j++)
matrix[i][j] += matrix[i][j-1] ; //按行改造成一维前缀和
for(int i=0; i<N; i++)
for(int j=0; j<M; j++)
for(int m=i; m<N; m++)
for(int n=j; n<M; n++)
max = Math.max(max, sumRegion(i,j,m,n)) ;
System.out.println(max);
private static long sumRegion(int row1, int col1, int row2, int col2)
long sum = 0 ;
for(int i=row1; i<=row2; i++)
if(col1>0)
sum += matrix[i][col2] - matrix[i][col1-1] ;
else
sum += matrix[i][col2] ;
return sum ;
H题:友谊纽带
思路:第一想到的思路是多源最短路,Floyd算法,不过由于是O(n^3)的复杂度,只能通过66.7%的测试用例,后面干脆用搜索,BFS的话,对所有顶点进行搜索,就是每一轮搜索,并标记搜索过的,如果一轮结束,还有没搜索到的,必然不连通,如果搜索到了,num记录当前节点与其余节点的最大值即可。AC代码如下:
import java.util.*;
public class Main
static int n, m ;
static List<Integer>[] edge ;
static int ans = 0 ;
static boolean [] vis ;
static boolean flag = false ;
public static void main(String[] args)
Scanner input = new Scanner(System.in) ;
n = input.nextInt() ;
m = input.nextInt() ;
edge = new List[n] ;
vis = new boolean [n] ;
for(int i=0; i<n; i++)
edge[i] = new ArrayList<>() ;
for(int i=0; i<m; i++)
int a = input.nextInt() ;
int b = input.nextInt() ;
edge[a-1].add(b-1) ;
edge[b-1].add(a-1);
for(int i=0; i<n; i++)
vis[i] = true ;
bfs(i) ;
for(int j=0; j<n; j++)
if(!vis[j])
flag = true ;
System.out.println(-1);
return ;
Arrays.fill(vis, false) ;
if(!flag)
System.out.println(ans);
private static void bfs(int i)
Queue<Integer> queue = new LinkedList<>() ;
queue.add(i) ;
int num = -1;
while(!queue.isEmpty())
num ++ ;
int size = queue.size() ;
for(int j=0; j<size; j++)
int x = queue.poll() ;
for(int y : edge[x])
if(!vis[y])
queue.add(y);
vis[y] = true;
ans = Math.max(ans, num) ;
Floyd算法代码如下,超时1ms,哈哈,我笑了,菜鸡互啄吧。就是用k节点更新i到j点的最短路。找出每个节点到其余节点的最短路,我用StreamTokenizer类替代Scanner类处理输入,Scanner类太慢了。
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StreamTokenizer;
public class Main
static int n, m ;
static int [][] dist ;
static int ans = 0 ;
static boolean flag = true ;
public static void main(String[] args) throws IOException
StreamTokenizer input = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in))) ;
input.nextToken() ;
n = (int) input.nval;
input.nextToken() ;
m = (int) input.nval ;
dist = new int [n][n] ;
for(int i=0; i<n; i++)
for(int j=0; j<n; j++)
dist[i][j] = n + 1 ;
for(int i=0; i<n; i++)
dist[i][i] = 0 ;
for(int i=0; i<m; i++)
input.nextToken() ;
int a = (int) input.nval;
input.nextToken() ;
int b = (int) input.nval;
dist[a-1][b-1] = 1 ;
dist[b-1][a-1] = 1 ;
for(int k=0; k<n; k++)
for(int i=0; i<n; i++)
for(int j=0; j<n; j++)
dist[i][j] = Math.min(dist[i][j], dist[i][k] + dist[k][j]);
for(int i=0; i<n; i++)
for(int j=0; j<n; j++)
if(dist[i][j]==n+1)
System.out.println(-1);
flag = false ;
return ;
else
ans = Math.max(dist[i][j], ans) ;
if(flag)
System.out.println(ans) ;
I题:传送门
思路:并查集判断联通性,最小生成树算法,对所有权值升序排序,每次取最小的,如果两个点不连通,则合并,直到取出n-1条边,则说明是联通的,找出最小生成树的最大权值边即是答案。
import java.util.*;
public class Main
static int N, M ;
static long ans = 0 ;
static int [] fa ;
static Edges [] edges ;
static boolean flag = false ;
public static void main(String[] args)
Scanner input = new Scanner(System.in) ;
N = input.nextInt() ;
M = input.nextInt() ;
fa = new int [N+1] ;
edges = new Edges [M] ;
for(int i=1; i<=N; i++)
fa[i] = i ;
for(int i=0; i<M; i++)
int u = input.nextInt() ;
int v = input.nextInt() ;
int w = input.nextInt() ;
edges[i] = new Edges(u,v,w) ;
solve() ;
if(flag)
System.out.println(ans);
else
System.out.println(-1);
private static void solve()
Arrays.sort(edges, new Comparator<Edges>()
@Override
public int compare(Edges o1, Edges o2)
return o1.w - o2.w;
) ;
int num = 1 ;
for(Edges edge : edges)
int u = edge.u, v = edge.v, w = edge.w ;
if(find(u) != find(v))
union(u, v) ;
num ++ ;
ans = Math.max(ans, w) ;
if(num == N)
flag = true ;
break ;
private static int find(int x)
if(x != fa[x])
fa[x] = find(fa[x]) ;
return fa[x] ;
private static void union(int x, int y)
int root1 = find(x) ;
int root2 = find(y) ;
fa[root1] = root2 ;
class Edges
int u, v, w;
public Edges (int u, int v, int w)
this.u = u ;
this.v = v ;
this.w = w ;
思路2;当然直接用并查集也就是可以的,按照权值升序排序,每次两个顶点不是一个集合,则合并,同时找出合并边中的最大值,如果最后所有顶点属于一个集合,说明联通,返回合并边中的最大值即是答案,否则不连通,返回-1.
import java.util.Arrays;
import java.util.Comparator;
import java.util.Scanner;
public class Main
static int N , M, num=0 ;
static Edge [] edges ;
static long ans = 0 ;
static int [] fa ;
public static void main(String[] args)
Scanner input = new Scanner(System.in) ;
N = input.nextInt() ;
M = input.nextInt() ;
fa = new int [N+1] ;
edges = new Edge[M] ;
for(int i=1; i<=N; i++)
fa[i] = i ;
for(int i=0; i<M; i++)
int u = input.nextInt() ;
int v = input.nextInt() ;
int w = input.nextInt() ;
edges[i] = new Edge(u,v,w) ;
f() ;
if(num==1)
System.out.println(ans);
else
System.out.println(-1);
private static void f()
Arrays.sort(edges, new Comparator<Edge>() //按权值升序排序
@Override
public int compare(Edge o1, Edge o2)
return o1.w - o2.w;
);
for(int i=0; i<M; i++)
int fu = find(edges[i].u) ;
int fv = find(edges[i].v) ;
if(fu!=fv)
ans = Math.max(ans, edges[i].w) ;
fa[fu] = fv ;
for(int i=1; i<=N; i++)
if(i==find(i))
num ++ ;
private static int find(int x)
if(x != fa[x])
fa[x] = find(fa[x]) ;
return fa[x] ;
class Edge
public int u, v, w;
public Edge(int u, int v, int w)
this.u = u ;
this.v = v ;
this.w = w ;
试题J:井字棋残局
思路:模拟过程就可以,说真话,不太好想。
import java.util.Scanner;
public class Main
static int [] arr ;
public static void main(String[] args)
Scanner input = new Scanner(System.in) ;
int t = input.nextInt() ;
for(int i=0; i<t; i++)
int n = input.nextInt() ;
arr = new int [10] ;
for(int j=1; j<=n; j++)
int x = input.nextInt() ;
int y = input.nextInt() ;
int idx = (x-1)*3 + (y-1) ; //映射成一维数组
arr[idx] = (j%2==1) ? 1 : -1 ; //对应的X和O
int ans = dfs(n+1) ;
if(ans == 1)
System.out.println("X");
else
if(ans==-1)
System.out.println("O");
else
System.out.println("-1");
private static int dfs(int x)
if(x==10)
if(check(1))
return 1 ;
else if(check(-1))
return -1 ;
else
return 0 ;
else
int who = (x%2 == 1 ? 1 : -1) ;
int win = 0, fail = 0, draw = 0 ;
for(int i=0;i<10;i++)
if(arr[i]==0)
arr[i] = who;
if(check(who)) win++;
else
int res = dfs(x+1);
if(res==who)
win++;
else if(who==-1*res)
fail++;
else
draw++;
arr[i] = 0;
return win>0?who:(draw>0?0:(-1*who));
private static boolean check(int x) //判断水平垂直和对角线
for(int i=0;i<3;i++)
if(arr[i*3]==x && arr[i*3+1]==x && arr[i*3+2]==x) return true;
if(arr[i]==x && arr[1*3+i]==x && arr[2*3+i]==x) return true;
return (arr[0]==x&&arr[4]==x&&arr[8]==x)||(arr[2]==x&&arr[4]==x&&arr[6]==x);
以上是关于九韶杯-题解(Java)的主要内容,如果未能解决你的问题,请参考以下文章