试题目录
A. 结果填空:有趣的数字(签到)
- 思路: 签到题,直接暴力循环并判断每个数是否既为质数又含有5。
Code:
import java.util.*;
import java.math.*;
public class Main{
static boolean isprime(int n) {
if(n==1 || n==0) return false;
for(int i=2;i*i<=n;i++) {
if(n%i==0)
return false;
}
return true;
}
static boolean check(int n) {
while(n>0) {
if(n%10==5) return true;
n/=10;
}
return false;
}
public static void main(String[] args){
int ans=0;
for(int i=1;i<=100000;i++) {
if(isprime(i) && check(i))
ans++;
}
System.out.println(ans);
}
}
B. 结果填空:爬楼梯(dp)
- 思路: 简单 dp
Code:
import java.util.*;
import java.math.*;
public class Main{
static int[] dp = new int[15];
public static void main(String[] args){
dp[0]=1; dp[1]=1;
dp[2]=2; dp[3]=4;
for(int i=4;i<=10;i++) {
if(i==5 || i==7) continue;
dp[i]=dp[i]+dp[i-1]+dp[i-2]+dp[i-3]+dp[i-4];
}
System.out.println(dp[10]);
}
}
C. 结果填空:七巧板(数论)
- 思路: 第一条直线最多可以划分出 6 个区域,以后每次划分比上次多划分一个区域出来,即 f[i] = f[i-1] + 1,故答案是47。
Code:
import java.util.*;
import java.math.*;
public class Main{
static int[] f = new int[10];
public static void main(String[] args){
int ans=7;
f[1]=6;
ans+=f[1];
for(int i=2;i<=5;i++) {
f[i]=f[i-1]+1;
ans+=f[i];
}
System.out.println(ans);
}
}
D. 结果填空:苹果(贪心)
- 思路: 有三种方法,分别是先取连续的三个 1,再取一个的 3 ;先取一个的 3 ,再取连续的三个 1;从左到右推过去,能取一个的 3 的就取,取完后再用后面两个篮子来凑连续的三个 1 ,答案分别是 58,57,62,故取最大的。下面只给出了第三种方案的代码。
Code:
import java.util.*;
import java.math.*;
public class Main{
static int[] a = new int[35];
public static void main(String[] args){
Scanner cin = new Scanner(System.in);
int ans=0;
for(int i=1;i<=30;i++)
a[i]=cin.nextInt();
for(int i=1;i<=30;i++) {
ans+=a[i]/3;
a[i]%=3;
while(a[i]>0 && a[i+1]>0 && a[i+2]>0) {
ans++;
a[i]--;a[i+1]--;a[i+2]--;
}
}
System.out.println(ans);
}
}
F. 程序设计:寻找重复项(HashMap)
- 思路: 这道题一开始直接模拟然后用数组标记一出现过的数值,但是只过了 6 个样例,因为数组一般只能定义到 1e7 的范围。所以用 HashMap 就不怕内存会超了。如果是用 C++ 的话,就得用 unorder_map ,不然 AC 不了。还有 记得全部用 long 型,否则还是过不了一些样例。
-感觉蓝桥杯好坑,又不能评测,又要在一次测试样例设坑!!!
Code:
import java.util.Scanner;
import java.util.HashMap;
public class Main{
static long[] f = new long[2000100];
public static void main(String[] args){
Scanner cin = new Scanner(System.in);
HashMap<Long,Long> mp = new HashMap<Long,Long>();
long a = cin.nextLong(), b = cin.nextLong(), c = cin.nextLong();
f[0] = 1;
mp.put(f[0],(long)1);
for(int i=1;i<=2000000;i++) {
f[i] = (f[i-1]*a+f[i-1]%b)%c;
if(mp.get(f[i])!=null) {
System.out.println(i);
return;
}else mp.put(f[i], (long)1);
}
System.out.println(-1);
}
}
G. 程序设计:被袭击的村庄(模拟)
- 思路: 这是一道差点要了我的命的模拟题。
- 首先答案应该弄错了,这个出题人确实该喷,这套题已经好多道题目答案弄错了(C、D题比赛时的答案错的,已经改了,而这道答案错了,至今还没改)。输出的应该是道路、房屋、田地耐久度分别为 0 的数目,以及整个村庄受到的总伤害。而不是输出道路、房屋、田地分别受到的伤害以及村庄受到的总伤害。
- 直接模拟,要注意的就是炸弹伤害那里的循环变量,要定义两个新的变量来表示炸弹范围里的坐标,而不是直接用地图的坐标。
- 最后,一开始因为有个细节写错了,导致改了很久,找不出bug(哭了)。但是数据很水,这个错误后来没改过来居然还给我过了。
- 直接用 C++ 吧,我累了,不想要再写一遍 Java 了。
Code:
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=0x3f3f3f3f;
const int pi=acos(-1.0);
const int mod=1e9+7;
int v[550][550],maps[550][550],life[550][550];
ll sum=0,d_sum=0,f_sum=0,t_sum=0;
int dx[8]={-1,-1,-1,0,0,1,1,1},dy[8]={1,0,-1,1,-1,1,0,-1};
int main(){
ll n,m; cin>>n>>m;
ll a,b,c; cin>>a>>b>>c;
ll k,w; cin>>k>>w;
for(int i=1;i<=k;i++)
for(int j=1;j<=k;j++)
cin>>v[i][j];
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>maps[i][j];
if(maps[i][j]==1) life[i][j]=a;
else if(maps[i][j]==2) life[i][j]=b;
else if(maps[i][j]==3) life[i][j]=c;
}
}
int q; cin>>q;
while(q--){
int id,x,y; cin>>id>>x>>y;
if(id==1){
for(int i=x-k/2,ii=1;i<=x+k/2,ii<=k;i++,ii++)
for(int j=y-k/2,jj=1;j<=y+k/2,jj<=k;j++,jj++){
if(i<=0 || i>n || j<=0 || j>m) continue;
if(life[i][j]){
if(life[i][j]>v[ii][jj]) life[i][j]-=v[ii][jj];
else life[i][j]=0;
}
}
}
else if(id==0){
for(int i=x-k/2,ii=1;i<=x+k/2,ii<=k;i++,ii++)
for(int j=y-k/2,jj=1;j<=y+k/2,jj<=k;j++,jj++){
if(i<=0 || i>n || j<=0 || j>m) continue;
if(life[i][j]){
if(life[i][j]>v[ii][jj]) life[i][j]-=v[ii][jj];
else life[i][j]=0;
}
for(int d=0;d<8;d++){
int xx=dx[d]+i,yy=j+dy[d];
if(xx<=0||yy<=0||xx>n||yy>m) continue;
if(life[xx][yy]){
if(life[xx][yy]<=w) life[xx][yy]=0;
else life[xx][yy]-=w;
}
}
}
}
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(maps[i][j]==1){
if(!life[i][j]) d_sum++;
sum+=(a-life[i][j]);
}
else if(maps[i][j]==2){
if(!life[i][j]) f_sum++;
sum+=(b-life[i][j]);
}
else if(maps[i][j]==3){
if(!life[i][j]) t_sum++;
sum+=(c-life[i][j]);
}
cout<<d_sum<<' '<<f_sum<<' '<<t_sum<<endl;
cout<<sum<<endl;
return 0;
}
H. 程序设计:字符串(模拟 + 取模)
- 思路: 先把字符串转换为 26 进制,转换的过程要对 m 取模,然后双重循环暴力遍历,对任意两个字符进行转换,把转换后的字符串与原始字符串的差值加上原始字符串的值,再加上 m (为了防止出现负数的情况,但数据比较少,没考虑这种情况),判断是否为 m 的倍数。这道题的难点我觉得在于取模,每一步能取模的都要取模,不然只能通过 6 个样例。
Code:
import java.util.Scanner;
public class Main{
static long m;
static long[] a = new long[2010];
static long change(String s) {
long ans=0;
for(int i=0;i<s.length();i++)
ans=(ans*26+s.charAt(i)-'A')%m;
return ans;
}
public static void main(String[] args){
Scanner cin = new Scanner(System.in);
String str = cin.next();
m = cin.nextInt();
int len = str.length();
a[len-1]=1;
for(int i=len-2;i>=0;i--)
a[i]=a[i+1]*26%m;
long ans = change(str);
if(ans==0) {
System.out.println("0 0");
return;
}
for(int i=0;i<len;i++) {
for(int j=i+1;j<len;j++) {
long res = (str.charAt(j)-str.charAt(i))*a[i]+(str.charAt(i)-str.charAt(j))*a[j];
if((ans+res+m)%m==0) { //加上m防止出现负数
System.out.println(++i + " " + ++j); //要用双引号
return;
}
}
}
System.out.println("-1 -1");
}
}