煤球数目
有一堆煤球,堆成三角棱锥形。具体:
第一层放1个,
第二层3个(排列成三角形),
第三层6个(排列成三角形),
第四层10个(排列成三角形),
....
如果一共有100层,共有多少个煤球?
题型
找规律
提取
三角棱锥形
共有多少个煤球
分析
复述
1到100层共有多少个煤球
思路
找规律
层数 | 所需煤球数 |
---|---|
1 | 1 |
2 | 3 |
3 | 6 |
4 | 10 |
5 | 15 |
得到规律
第n层煤球数=第n-1层煤球数+n
模拟
时间复杂度
O(100)
收获
class MC{
public void run(){
//s:当前总煤球数目, n当前层的煤球数目
int s = 0, n = 0;
for (int i = 1; i <= 100; i++) {
n += i;
s += n;
}
System.out.println(s);
}
}
public class Main {
public static void main(String[] args) {
new MC().run();
}
}
生日蜡烛
题目描述
某君从某年开始每年都举办一次生日party,并且每次都要吹熄与年龄相同根数的蜡烛。
现在算起来,他一共吹熄了236根蜡烛。
请问,他从多少岁开始过生日party的?
输出格式
请填写他开始过生日party的年龄数。
ti
提取
每年都举办一次生日party,每次都要吹熄与年龄相同根数的蜡烛
他一共吹熄了236根蜡烛
他从多少岁开始过生日party的
分析
设他从k岁过生日的,过了n个生日,则有k + (k + 1) + … + (k + n - 1) = 236
复述
给你某段区间和,前后元素之差为1,求区间的左端点
思路
有两个未知数,一个是n,另一个是左端点l,我们可以暴力枚举n和l的出答案
但提到区间和,就想到前缀和,求前缀和后,我们也可以枚举左右端点得到答案
模拟
时间复杂度
O ( 100 + 10 0 2 ) O(100 + 100^2) O(100+1002)
收获
class MC{
public void run(){
int[] s = new int[110];
for (int i = 1; i <= 100; i++) {
s[i] = i;
s[i] += s[i - 1];
}
for (int i = 1; i <= 100; i++) {
for (int j = 100; j >= i; j--) {
if(s[j] - s[i - 1] == 236){
System.out.println(i);
break;
}
}
}
}
}
public class Main {
public static void main(String[] args) {
new MC().run();
}
}
凑算式
全排列+分母通分
s1: A, s2:B, s3:C, s4:DEF, s5:GHI
class MC{
int N = 11, n = 9;
int[] a = new int[N];
boolean[] st = new boolean[N];
int res = 0;
boolean check() {
int s1 = a[1];
int s2 = a[2], s3 = a[3];
int s4 = a[4] * 100 + a[5] * 10 + a[6], s5 = a[7] * 100 + a[8] * 10 + a[9];
int r2 = s3 * s5;
s2 = s2 * s5;
s4 = s4 * s3;
s1 = s1 * r2;
return (s1 + s2 + s4) % r2 == 0 && (s1 + s2 + s4) / r2 == 10;
}
void dfs(int cnt){
if(cnt == n + 1){
if (check()) res++;
return;
}
for (int i = 1; i <= n; i++) {
if (st[i]) continue;
st[i] = true;
a[cnt] = i;
dfs(cnt + 1);
st[i] = false;
}
}
public void run(){
dfs(1);
System.out.println(res);
}
}
public class Main {
public static void main(String[] args) {
new MC().run();
}
}
方格填数
什么?你在问我有没有技巧?不存在的,全排列完事
class MC{
int N = 13, n = 10;
int[] a = new int[N];
boolean[] st = new boolean[N];
int res = 0;
boolean h(int a, int...ints){
int l1 = a - 1, l2 = a + 1;
for (int i : ints) {
if (l1 == i || l2 == i) return false;
}
return true;
}
boolean check(){
boolean f = true;
if(!h(a[1], a[2], a[4], a[5], a[6])) f = false;
if(!h(a[2], a[1], a[3], a[5], a[6], a[7])) f = false;
if(!h(a[3], a[2], a[6], a[7])) f = false;
if(!h(a[4], a[1], a[5], a[8], a[9])) f = false;
if(!h(a[5], a[1], a[2], a[4], a[6], a[8], a[9], a[10])) f = false;
if(!h(a[6], a[1], a[2], a[3], a[5], a[7], a[9], a[10])) f = false;
if(!h(a[7], a[2], a[3], a[6], a[10])) f = false;
if(!h(a[8], a[4], a[5], a[9])) f = false;
if(!h(a[9], a[4], a[5], a[6], a[8], a[10])) f = false;
if(!h(a[10], a[5], a[6], a[7], a[9])) f = false;
return f;
}
void dfs(int cnt){
if (cnt == n + 1){
if(check()) res++;
return;
}
for (int i = 0; i < n; i++) {
if(st[i]) continue;
st[i] = true;
a[cnt] = i;
dfs(cnt + 1);
st[i] = false;
}
}
public void run(){
dfs(1);
System.out.println(res);
}
}
public class Main {
public static void main(String[] args) {
new MC().run();
}
}
剪邮票
暂留
import java.io.IOException;
class MC {
int N = 20;
boolean[] st = new boolean[N];
int[] arr = new int[N];
int k1 = 12, k2 = 5;
int[][] d = new int[][]{{0, 1}, {0, -1}, {1, 0},{-1, 0}};
int res;
int[] toP(int k, int p){
int[] r = new int[2];
if (k % p == 0){
r[0] = k / p;
r[1] = p;
}else {
r[0] = k / p + 1;
r[1] = k % p;
}
return r;
}
void df(int[][] g, int x, int y){
g[x][y] = 0;
for (int i = 0; i < 4; i++) {
int tx = x + d[i][0], ty = y + d[i][1];
if (tx < 1 || ty < 1 || tx > 3 || ty > 4) continue;
if (g[tx][ty] == 1) df(g, tx, ty);
}
}
void check(){
int[][] g = new int[N][N];
for (int i = 1; i <= 5; i++) {
int[] p = toP(arr[i], 4);
g[p[0]][p[1]] = 1;
}
//连通性检查
int cnt = 0;
for (int i = 1; i <= 3; i++) {
for (int j = 1; j <= 4; j++) {
if (g[i][j] == 1) {
df(g, i, j);
cnt ++;
}
}
}
if (cnt == 1) res++;
}
void dfs(int cnt){
if (cnt == k2 + 1){
check();
return;
}
for (int i = 1; i <= k1; i++) {
if(st[i] || i < arr[cnt - 1]) continue;
st[i] = true;
arr[cnt] = i;
dfs(cnt + 1);
st[i] = false;
}
}
public void run() throws IOException {
dfs(1);
System.out.println(res);
}
}
public class Main {
public static void main(String[] args) throws IOException {
new MC().run();
}
}
四平方和
import java.io.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
class MC {
//0 <= a <= b <= c <= d
//a*a: [0, n / 4]
//b*b: [0, n / 3]
//c*c: [0, n / 2]
//d*d: [0, n]
int n;
void handle(){
Map<Integer, Integer> cache = new HashMap<>();
for (int c = 0; c * c <= n / 2; c++) {
for (int d = c; c * c + d * d <= n; d++) {
//先出现的字典序一定小
if (!cache.containsKey(c * c + d * d)) cache.put(c * c + d * d, c);
}
}
for (int a = 0; a * a <= n / 4; a++) {
for (int b = a; a * a + b * b <= n / 3; b++) {
int t = n - a * a - b * b;
if (cache.containsKey(t)){
Integer c = cache.get(t);
int d = (int) Math.sqrt(t - c * c);
try {
bw.write(String.format("%d %d %d %d\n", a, b, c, d));
bw.flush();
} catch (IOException e) {
e.printStackTrace();
}
return;
}
}
}
}
public void run() throws IOException {
//直接枚举四个肯定超时
//优化枚举方法有两个,一个是减少枚举变量,一个是空间换时间
//减少枚举d还是会超时,只能用缓存
while (true){
try {
n = Integer.parseInt(br.readLine());
handle();
}catch (Exception e){
break;
}
}
}
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
}
public class Main {
public static void main(String[] args) throws IOException {
new MC().run();
}
}
取球博弈
import java.io.IOException;
import java.util.Arrays;
import java.util.Scanner;
class MC {
int N = 10;
int[] a = new int[N];
/**
* 优化思路,缓存
*/
int[][][] cache = new int[1000][2][2];
/**
* 给定球数,我方是否先手必胜
* @param num 现有球数
* @param me 自己的球数
* @param you 对手的球数
* @return int值
*/
int f(int num, int me, int you){
//不够取,递归出口
//如果无法继续取球,则游戏结束。
if (num < a[1]){
//自己有奇数个,对手有偶数个,我赢
if((me & 1) == 1 && (you & 1) == 0) return 1;
//自己有偶数个,对手有奇数个,我输
else if ((me & 1) == 0 && (you & 1) == 1) return -1;
//平局
return 0;
}
//查缓存
if (cache[num][me][you] != 3) return cache[num][me][you];
boolean ping = false;
//计算机也不知道取哪个最优,只好1个1个试
for (int i = 1; i <= 3; i++) {
//当前场上球数量够,可以试一下
if (num >= a[i]) {
//我拿了a[i]个球,轮到对手拿球
//这里的res是对手拿球之后的结果,是对对手而言的
//谁在中间的参数上就是对谁而言,因为函数定义是如此
int res = f(num - a[i], you & 1, (me + a[i]) & 1);
//只要对手输,我赢
//最终局面一旦有对手输,因为我是最聪明的,一定会选择我赢的局面
//所以只要对手有输的可能我就赢
if (res == -1) return 1;
//最终局面也有可能是我赢,但没有意义,只要存在我输的可能,对手一定会使我输
//为什么这里平局不能直接return呢
//因为还有其他局面使得我输或我赢
if (res == 0) ping = true;
}
}
//代码走到这里说明不存在对手输,要么是对手赢,要么是平局
if (ping) {
cache[num][me][you] = 0;
return 0;
}
else {
cache[num][me][you] = -1;
return -1;
}
}
void init(){
for (int[][] ints : cache) {
for (int[] anInt : ints) {
Arrays.fill(anInt, 3);
}
}
}
public void run() throws IOException {
for (int i = 1; i <= 3; i++) {
a[i] = sc.nextInt();
}
Arrays.sort(a, 1, 4);
for (int i = 0; i < 5; i++) {
init();
int num = sc.nextInt();
int r = f(num, 0, 0);
char cr = '0';
if (r == 1) {
cr = '+';
} else if (r == -1) {
cr = '-';
}
System.out.print(cr + " ");
}
}
Scanner sc = new Scanner(System.in);
}
public class Main {
public static void main(String[] args) throws IOException {
new MC().run();
}
}