- 购物单
思路:掏出计算器或者把数据处理一下计算,注意每次最少只能取100,结果是5136.85,应该取5200
答案:5200 - 纸牌三角形
答案:144
分析:
题目要求三角形三边和都相等。假设把这个三角形按照从左向右的顺序映射到一位数组0 - 8
那么只需要各个边的和a[0,1,2,3] == a[3,4,5,6] == a[6,7,8,0]
三角形可以旋转和镜像都算同一种情况,一种三角形有镜像和非镜像2种情况,通过旋转可以得到3种三角形,那么每次共有6种情况。
可以通过对1 - 9 全排列找出所有满足条件的情况,再除6
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.Vector;
public class Main{
static int p[] = new int[15];
static int a[] = {1,2,3,4,5,6,7,8,9};
static boolean st[] = new boolean[15];
static Set<String> S = new HashSet<String>();
static long res = 0;
public static void main(String[] args) throws NumberFormatException, IOException {
BufferedReader cin = new BufferedReader(new InputStreamReader(System.in));
dfs(0);
System.out.println(res/6);
}
static void dfs(int k) {
if(k == 9) {
if(check()) res++;
return;
}
for(int i = 0; i < 9; i++) {
if(st[i]) continue;
p[k] = a[i];
st[i] = true;
dfs(k+1);
st[i] = false;
}
}
static boolean check() {
int a = p[0] + p[1] + p[2] + p[3];
int b = p[3] + p[4] + p[5] + p[6];
int c = p[6] + p[7] + p[8] + p[0];
return a == b && b == c;
}
}
- 承压计算
答案:72665192664
分析:每块金属都会把它的重量均匀的分到它下一层的左边和右边。
假设 f[i][j] = w; 它的重量的一半w/2就会分别分到 f[i+1][j] 和 f[i+1][j+1]
只需要找出最底层的最大重量max 和 min,根据转换
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;
import java.util.Vector;
public class Main{
static double p[][] = new double[35][35];
static double f[][] = new double[35][35];
public static void main(String[] args) throws NumberFormatException, IOException {
BufferedReader cin = new BufferedReader(new InputStreamReader(System.in));
Scanner sc = new Scanner(System.in);
// for(int i = 1; i <= 29; i++) {
// for(int j = 1; j <= i; j++) {
// f[i][j] = sc.nextDouble();
// }
// }
// for(int i = 1; i <= 29; i++) {
// for(int j = 1; j <= i; j++) {
// f[i+1][j] += f[i][j] / 2;
// f[i+1][j+1] += f[i][j] / 2;
// }
// }
// double Max = 0, Min = 9999999.0;
// for(int i = 1; i <= 30; i++) {
// Max = Math.max(Max, f[30][i]);
// Min = Math.min(Min, f[30][i]);
// }
// System.out.println(Max+" "+Min);
//System.out.println((long)(2086458231L * (Max / Min)));
System.out.println(72665192664L);
}
}
-
魔方状态
答案:229878
这题我直接放弃~~~~~~~~~~~~ -
最大公共子串(DP)
答案:a[i-1][j-1] + 1
分析:假设定义a[i][j] 表示的是长度为i 和长度为j 的字符串的最大公共子串的长度,当c1[i] == c2[j] ,最后一个字符是不变的,我们只需要看看变的部分是最大公共子串的长度是多少在+1。即变的部分是前a[i-1][j-1], 根据定义表示的是长度为i-1和j-1的字符串的最大公共子串的最大值
-
日期问题(枚举)
判断是闰年:(year % 100 != 0 && year % 4 == 0) || year % 400 == 0
代码1:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Main {
static int days[] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
static boolean check(int year,int month, int day) {
if(month < 1 || month > 12) return false;
if(day == 0 || month != 2 && day > days[month]) return false;
if(month == 2) {
int flag = 0;
if(year % 100 != 0 && year % 4 == 0 || year % 400 == 0) flag = 1;
if(day > 28 + flag) return false;
}
return true;
}
public static void main(String[] args) throws IOException {
BufferedReader cin = new BufferedReader(new InputStreamReader(System.in));
String str[] = cin.readLine().split("/");
int a = Integer.parseInt(str[0]);
int b = Integer.parseInt(str[1]);
int c = Integer.parseInt(str[2]);
for(int i = 19600101; i <= 20591231; i++) {
int year = i / 10000;
int month = i / 100 % 100;
int day = i % 100;
if(check(year,month,day)) {
if((year%100 == a && month == b && day == c) ||
(month == a && day == b && year%100 == c) ||
(day == a && month == b && year%100 == c)) {
System.out.println(String.format("%d-%02d-%02d", year,month,day));
}
}
}
}
}
代码2:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Main {
static int days[] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
static boolean check(int year,int month, int day) {
if(month < 1 || month > 12) return false;
if(day == 0 || month != 2 && day > days[month]) return false;
if(month == 2) {
int flag = 0;
if(year % 100 != 0 && year % 4 == 0 || year % 400 == 0) flag = 1;
if(day > 28 + flag) return false;
}
return true;
}
public static void main(String[] args) throws IOException {
BufferedReader cin = new BufferedReader(new InputStreamReader(System.in));
String str[] = cin.readLine().split("/");
int a = Integer.parseInt(str[0]);
int b = Integer.parseInt(str[1]);
int c = Integer.parseInt(str[2]);
for(int i = 1960; i <= 2059; i++) {
for(int j = 1; j <= 12; j++) {
//年月日
if(a == i % 100 && b == j) {
if(check(i,j,c))
System.out.println(String.format("%d-%02d-%02d",i,j,c));
}else if(a == j && c == i % 100) {//月日年
if(check(i,j,b))
System.out.println(String.format("%d-%02d-%02d",i,j,b));
}else if(b == j && c == i % 100) {//日月年
if(check(i,j,a))
System.out.println(String.format("%d-%02d-%02d",i,j,a));
}
}
}
}
}
- 包子凑数(完全背包+数论)
1、(a1,a2,…,an) = d > 1 (最大公约数),那么只要不是d的倍数就不能被凑出来,所以有INF个。
2、(a1,a2,…,an) = 1,说明它们不能凑出的数一定是有限个。
==》这里用到裴蜀定理 ,任意两个数的组合必定是他们gcd的倍数,同样可以推广到更多数:如果这些数的gcd是是d,那么他们的组合是d的倍数,如果d不是1,那么必然有无限个数无法被组合出来。
==》公式:当gcd(a,b) = 1, 那么a和b是互质的,a,b最大不能表示出的数是(a-1)*(b-1) - 1
99和98是100内最大的互质的数,不超过10000,那么上界我们就取10000。
因此可以在1 - 10000里面考虑不能被凑出来的数
完全背包:
凑的数 ==》背包容量, Ai 表示物品
朴素版代码
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Main {
static int N = 10010;
static int n;
static boolean f[][] = new boolean[110][N];
static int a[] = new int[N];
static int gcd(int a,int b) {
return b == 0 ? a : gcd(b,a%b);
}
public static void main(String[] args) throws NumberFormatException, IOException {
BufferedReader cin = new BufferedReader(new InputStreamReader(System.in));
n = Integer.parseInt(cin.readLine());
int d = 0;
for(int i = 1; i <= n; i++) {
a[i] = Integer.parseInt(cin.readLine());
d = gcd(d,a[i]);
}
if(d != 1) System.out.println("INF");
else {
f[0][0] = true;
for(int i = 1; i <= n; i++)
for(int j = 0; j < N; j++) {
f[i][j] = f[i-1][j];
if(j >= a[i]) f[i][j] = f[i][j] | f[i][j - a[i]];
}
int res = 0;
for(int i = 0; i < N; i++)
if(!f[n][i]) res++;
System.out.println(res);
}
}
}
优化空间:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Main {
static int N = 10010;
static int n;
static boolean f[] = new boolean[N];
static int a[] = new int[N];
static int gcd(int a,int b) {
return b == 0 ? a : gcd(b,a%b);
}
public static void main(String[] args) throws NumberFormatException, IOException {
BufferedReader cin = new BufferedReader(new InputStreamReader(System.in));
n = Integer.parseInt(cin.readLine());
int d = 0;
for(int i = 1; i <= n; i++) {
a[i] = Integer.parseInt(cin.readLine());
d = gcd(d,a[i]);
}
if(d != 1) System.out.println("INF");
else {
f[0] = true;
for(int i = 1; i <= n; i++)
for(int j = a[i]; j < N; j++)
f[j] = f[j] | f[j - a[i]];
int res = 0;
for(int i = 0; i < N; i++)
if(!f[i]) res++;
System.out.println(res);
}
}
}
- 分巧克力(二分)
分析:题目要求在保证每个人最、至少得到一块巧克力的前提下尽可能把巧克力切的更大。
假设我们确定边长x,那么只需要判断n块巧克力能不能切出边长为x的巧克力的数量是否大于k。
根据数据范围,x最小为1,最大为100000,所求的答案在1 - 100000里,二分枚举。
代码:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Scanner;
public class Main{
static int N = 100010;
static int n,m;
static int h[] = new int[N];
static int w[] = new int[N];
static boolean check(int mid) {
int res = 0;
for(int i = 0; i < n; i++)
res += (h[i] / mid) * (w[i] / mid);
return res >= m;
}
public static void main(String[] args) throws NumberFormatException, IOException {
BufferedReader cin = new BufferedReader(new InputStreamReader(System.in));
String str[] = cin.readLine().split(" ");
n = Integer.parseInt(str[0]);
m = Integer.parseInt(str[1]);
for(int i = 0; i < n; i++) {
str = cin.readLine().split(" ");
h[i] = Integer.parseInt(str[0]);
w[i] = Integer.parseInt(str[1]);
}
int l = 0, r = 1000000;
while(l < r) {
int mid = l + r + 1>> 1;
if(check(mid)) l = mid;
else r = mid - 1;
}
System.out.println(l);
}
}
- K倍区间(前缀和)
暴力算法(n^2 + 前缀和)
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Main {
static int N = 100010;
static long s[] = new long[N];
static long cnt[] = new long[N];
static int n,k;
public static void main(String[] args) throws IOException {
BufferedReader cin = new BufferedReader(new InputStreamReader(System.in));
String str[] = cin.readLine().split(" ");
n = Integer.parseInt(str[0]);
k = Integer.parseInt(str[1]);
for(int i = 1; i <= n; i++) {
s[i] = Long.parseLong(cin.readLine());
s[i] += s[i-1];
}
long res = 0;
for(int l = 1; l <= n; l++)
for(int r = l; r <= n; r++)
if((s[r] - s[l-1]) % k == 0) res++;
System.out.println(res);
}
}
优化版(O(n) + 前缀和)
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Main {
static int N = 100010;
static long s[] = new long[N];
static long cnt[] = new long[N];
static int n,k;
public static void main(String[] args) throws IOException {
BufferedReader cin = new BufferedReader(new InputStreamReader(System.in));
String str[] = cin.readLine().split(" ");
n = Integer.parseInt(str[0]);
k = Integer.parseInt(str[1]);
for(int i = 1; i <= n; i++) {
s[i] = Long.parseLong(cin.readLine());
s[i] += s[i-1];
}
long res = 0;
cnt[0]++;
for(int i = 1; i <= n; i++) {
res += cnt[(int)(s[i] % k)];
cnt[(int)(s[i] % k)]++;
}
System.out.println(res);
}
}
C++组题目:
标题:等差素数列(DFS)
答案:210
分析:暴力枚举,先把10000以内的素数找出来放到st,暴搜的时候直接查。
我们要找长度为数列长度为10的数列且公差最小,那么从小到大枚举公差,确定一个公差的值后,再枚举素数,每次加上公差,当枚举出的素数个数为10的时候,此时的d就是最小的公差。
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Main {
static boolean st[] = new boolean[100010];
static int p[] = new int[20];
static boolean is_prime(int x) {
for(int i = 2; i <= x / i; i++)
if(x % i == 0) return false;
return true;
}
static void dfs(int k,int x,int d) {
if(k == 10) {
System.out.println(d);
for(int i = 0; i < 10; i++) System.out.print(p[i]+" ");
System.out.println();
return;
}
if(st[x+d]) {
p[k] = x + d;
dfs(k+1,x+d,d);
}
}
public static void main(String[] args) throws NumberFormatException, IOException {
BufferedReader cin = new BufferedReader(new InputStreamReader(System.in));
int arr[] = new int[10000];
int t = 0;
for(int i = 2; i < 100000; i++)
if(is_prime(i)) st[i] = true;
for(int d = 2; d <= 500; d++) {
for(int j = 2; j <= 500; j++) {
p[0] = j;
if(st[j]) dfs(1,j,d);
}
}
//System.out.println(210);
}
}
标题:方格分割(DFS)
答案:509
分析:从其他大佬处学到的方法
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Main {
static boolean st[][] = new boolean[10][10];
static int dx[] = {0,1,0,-1};
static int dy[] = {1,0,-1,0};
static int res = 0;
static void dfs(int x,int y) {
if(x == 0 || y == 0 || x == 6 || y == 6) {
res++;
return;
}
for(int i = 0; i < 4; i++) {
int a = x + dx[i];
int b = y + dy[i];
if(a < 0 || a > 6 || b < 0 || b > 6) continue;
if(st[a][b]) continue;
st[a][b] = st[6-a][6-b] = true;
dfs(a,b);
st[a][b] = st[6-a][6-b] = false;
}
}
public static void main(String[] args) throws NumberFormatException, IOException {
BufferedReader cin = new BufferedReader(new InputStreamReader(System.in));
st[3][3] = true; //注意点
dfs(3,3);
System.out.println(res/4);
}
}