1.【结果填空】 标题:海盗分金币
有5个海盗,相约进行一次帆船比赛。
比赛中天气发生突变,他们被冲散了。
恰巧,他们都先后经过途中的一个无名的荒岛,并且每个人都信心满满,觉得自己是第一个经过该岛的人。
第一个人在沙滩上发现了一堆金币。他把金币分成5等份。发现刚好少一个金币。他就从自己口袋拿出一个金币补充进去,然后把属于自己的那份拿走。
第二个到达的人也看到了金币,他也和第一个人一样,把所有金币5等分,发现刚好缺少一个金币,于是自己补进去一个,拿走了属于自己的那份。
第三,第四,第五人的情况一模一样。
等他们到了目的地,都说自己的情况,才恍然大悟,一起去荒岛找金币,然而再也没有找到荒岛。他们都惋惜地说:岛上还有一千多枚金币呢!
请你根据这些信息,推算荒岛上最初有多少金币?
这是一个整数,请通过浏览器提交答案,不要填写任何多余的内容(比如说明性的文字等)
答案:3129
暴破,注意最后一句话是说还剩下1k多金币,也就是一开始至少有1k多金币,暴力的起点也就有了,再用递归进行整除判断,还要满足最后剩下1k多金币。
public class G201401 {
static boolean solve(int x, int cnt){
if(x <= 0) return false;
x++;
if(x%5 != 0)
return false;
else {
if(cnt == 4) {
if((x-x/5) >= 1000 && (x-x/5) < 2000) //剩下
return true;
return false;
}
if(solve(x-x/5, cnt+1)) return true;
else return false;
}
}
public static void main(String[] args) {
for(int i = 1000; i<=20000; i++){
if(solve(i, 0)) System.out.println(i);
}
}
}
2.【结果填空】 标题:六角幻方
把 1 2 3 ... 19 共19个整数排列成六角形状,如下: * * * * * * * * * * * * * * * * * * * 要求每个直线上的数字之和必须相等。共有15条直线哦! 再给点线索吧!我们预先填好了2个数字,第一行的头两个数字是:15 13,参见图【p1.png】,黄色一行为所求。 请你填写出中间一行的5个数字。数字间用空格分开。
这是一行用空格分开的整数,请通过浏览器提交答案,不要填写任何多余的内容(比如说明性的文字等)
答案:9 6 5 2 16
稍微复杂一点的dfs,特别要注意剪枝,不然时间复杂度O(n!)高的吓人。。以及变量比较多,我用的一维数组存储,打变量名的时候要特别小心。。剪枝有一点小技巧,就是不要一次性的排列好之后再判断,因为这个的复杂度太高,在排列过程中就要进行剪枝判断。。最后,由于1-19的和是确定的,所以可以求出任一行、列或者对角线的和=(1+19)*19/2 / 5 = 38.
#include<bits/stdc++.h>
using namespace std;
int a[16]={1,2,3,4,5,6,7,8,9,11,12,14,16,17,18,19};
bool vis[16];
int b[16];
void print(){
cout<<15<<" "<<13<<" "<<10<<endl;
cout<<b[0]<<" "<<b[1]<<" "<<b[2]<<" "<<b[3]<<endl;
cout<<b[4]<<" "<<b[5]<<" "<<b[6]<<" "<<b[7]<<" "<<b[8]<<endl;
cout<<b[9]<<" "<<b[10]<<" "<<b[11]<<" "<<b[12]<<endl;
cout<<b[13]<<" "<<b[14]<<" "<<b[15]<<endl;
cout<<endl;
}
void dfs(int cur){
if(cur == 16){
if(b[1]+b[6]+b[11]+b[15]+15 != 38) return;
if(b[13]+b[14]+b[15] != 38) return;
if(b[15]+b[12]+b[8] != 38) return;
print();
return ;
}
if(cur == 4){
if(b[0]+b[1]+b[2]+b[3] != 38) return;
}
if(cur == 5){
if(b[0]+b[4]+15 != 38) return;
}
if(cur == 9){
if(b[3]+b[8]+10 != 38) return;
if(b[4]+b[5]+b[6]+b[7]+b[8] != 38) return;
}
if(cur == 10){
if(b[9]+b[5]+b[1]+13 != 38) return;
}
if(cur == 13){
if(13+b[12]+b[2]+b[7] != 38) return;
if(b[9]+b[10]+b[11]+b[12] != 38) return;
}
if(cur == 14){
if(b[13]+b[10]+b[6]+b[2]+10 != 38) return;
if(b[9]+b[4]+b[13] != 38) return;
}
if(cur == 15){
if(b[14]+b[11]+b[7]+b[3] != 38) return;
if(b[0]+b[5]+b[10]+b[14] != 38) return;
}
for(int i = 0; i<16; i++){
if(!vis[i]){
vis[i] = true;
b[cur] = a[i];
dfs(cur+1);
vis[i] = false;
}
}
}
int main(){
dfs(0);
return 0;
}
3.【代码填空】 格子放鸡蛋
X星球的母鸡很聪明。它们把蛋直接下在一个 N * N 的格子中,每个格子只能容纳一枚鸡蛋。它们有个习惯,要求:每行,每列,以及每个斜线上都不能有超过2个鸡蛋。如果要满足这些要求,母鸡最多能下多少蛋呢,有多少种摆放方法呢?
下面的程序解决了这个问题,请仔细分析程序逻辑,推断划线处缺少的代码。
public class A
{
static int max = 0;
static int T = 0;
static final int N = 6;
// 只能在(r,c) 以及其右,其下放置
static void f(int[][] da, int r, int c)
{
if(r>=N){
int n = count(da);
if(n>max) {
max = n;
T = 0;
}
if(n==max) T++;
return;
}
//计算一下步放哪
int r_next = r;
int c_next = c + 1;
if(c_next>=N){
c_next = 0;
r_next++;
}
if(____________________){ // 填空位置
da[r][c] = 1;
f(da, r_next, c_next);
}
da[r][c] = 0;
f(da, r_next, c_next);
}
static int count(int[][] da)
{
int n = 0;
for(int i=0; i<da.length; i++)
for(int j=0; j<da[i].length; j++)
if(da[i][j]==1) n++;
return n;
}
static int spy(int[][] da, int r, int c)
{
int m=0;
// 该行
int n=0;
for(int i=0; i<N; i++) if(da[r][i]==1) n++;
if(n>m) m = n;
//该列
n=0;
for(int i=0; i<N; i++) if(da[i][c]==1) n++;
if(n>m) m = n;
//右斜线
n=0;
for(int i=0; i<N; i++){
if(r-i<0 || c-i<0) break;
if(da[r-i][c-i]==1) n++;
}
for(int i=1; i<N; i++){
if(r+i>=N || c+i>=N) break;
if(da[r+i][c+i]==1) n++;
}
if(n>m) m = n;
//左斜线
n=0;
for(int i=0; i<N; i++){
if(r-i<0 || c+i>=N) break;
if(da[r-i][c+i]==1) n++;
}
for(int i=1; i<N; i++){
if(r+i>=N || c-i<0) break;
if(da[r+i][c-i]==1) n++;
}
if(n > m) m = n;
return m;
}
public static void main(String[] args)
{
int[][] da = new int[N][N];
f(da, 0, 0);
System.out.println(max);
System.out.println(T);
}
}
注意:通过浏览器提交答案。只填写缺少的内容,不要填写任何多余的内容(例如:说明性文字或已有符号)。
答案:spy(da, r, c) < 2
分析:有点八皇后的味道。。观察到spy()方法没有用上,所以此空一定和spy()方法有关,以及仔细看spy()方法发现返回的是行、列或者斜线上有的鸡蛋的最大个数。以及题目要求不能超过2,结合一下答案就出来了。
4.【编程大题】 标题:排列序数
如果用a b c d这4个字母组成一个串,有4!=24种,如果把它们排个序,每个串都对应一个序号:
abcd 0
abdc 1
acbd 2
acdb 3
adbc 4
adcb 5
bacd 6
badc 7
bcad 8
bcda 9
bdac 10
bdca 11
cabd 12
cadb 13
cbad 14
cbda 15
cdab 16
cdba 17
…
现在有不多于10个两两不同的小写字母,给出它们组成的串,你能求出该串在所有排列中的序号吗?【输入格式】
一行,一个串。【输出格式】
一行,一个整数,表示该串在其字母所有排列生成的串中的序号。注意:最小的序号是0。例如:
输入:
bdca程序应该输出:
11再例如:
输入:
cedab程序应该输出:
70资源约定:
峰值内存消耗(含虚拟机) < 256M
CPU消耗 < 1000ms
请严格按要求输出,不要画蛇添足地打印类似:“请您输入…” 的多余内容。
所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意:不要使用package语句。不要使用jdk1.7及以上版本的特性。
注意:主类的名字必须是:Main,否则按无效代码处理。
乍看这么眼熟,原来之前做的2017蓝桥模拟,天梯赛中都出现了类似的,不过之前是用的暴力的dfs,(流下了只会暴力的泪水.jpg)之前蓝桥模拟那题实际上暴力dfs没跑出来,因为。。。时间复杂度实在是太高。。后来才知道这题算是数论的题,要用到康托展开,(再次流下不学无术的泪水.jpg),其实康托展开(见下式)非常实用,一开始接触可能有点恐惧,慢慢搞清楚就好,(真的好用。
X=an*(n-1)!+an-1*(n-2)!+…+ai*(i-1)!+…+a2*1!+a1*0!
公式说明:ai为第i位数是在后面所有数(含ai)中的第几小(从0开始编号)的数。举个例子,A={b,a,d,c}
- 对于b而言,i等于n,b要进行比较的集合是{a,d,c},b在其中排第1位,an=1
- 对于a而言,i等于n-1,a要进行比较的集合是{d,c},a在其中排第0位,an-1=0
- 对于d而言,i等于n-2,d要进行比较的集合是{c},d在其中排第1位,an-2=1
- 最后对于c而言,i等于n-3,c没有要比较的数,an-3=0
所以对于上例,X=1*3!+0*2!+1*1!+0*0!=7,理解之后代码就非常之简单了。
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;
public class G201404 {
static StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
static PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
static long[] Fac = new long[12];
static int[] a = new int[12];
static void getF(int x){
Fac[1] = 1;
for(int i = 2; i<=x; i++ ){
Fac[i] = i*Fac[i-1];
}
}
static void getA(String string){
for(int i = 0; i<string.length(); i++){
int sum = 0;
for(int j = i+1; j<string.length(); j++){
if(string.charAt(i) > string.charAt(j)) sum++;
}
a[i] = sum;
}
}
public static void main(String[] args) throws IOException{
in.nextToken();
String string = in.sval;
getF(10);
getA(string);
long res = 0;
for(int i = 0; i<string.length(); i++){
res += Fac[string.length() - i - 1]*a[i];
}
out.println(res);
out.flush();
}
}
5.【编程大题】 标题:幂一矩阵
天才少年的邻居 atm 最近学习了线性代数相关的理论,他对“矩阵”这个概念特别感兴趣。矩阵中有个概念叫做幂零矩阵。对于一个方阵 M ,如果存在一个正整数 k 满足 M^k = 0 ,那么 M 就是一个幂零矩阵。(^ 表示乘方)
atm 不满足幂零矩阵,他自己设想了一个幂一矩阵:对于一个方阵 M ,如果存在一个正整数 k 满足 M^k = I ,其中 I 是单位矩阵,那么 M 就是一个幂一矩阵。
atm 特别钟情于这样一种方阵:每行每列有且仅有一个 1 。经过 atm 不断实验,他发现这种矩阵都是幂一矩阵。
现在,他的问题是,给定一个满足以上条件的方阵,他想求最小的 k 是多少。
【输入格式】
第一行一个正整数 n ,表示矩阵大小是 n * n 。
接下来 n 行,每行两个正整数 i j 表示方阵的第 i 行第 j 列为 1。
1 <= i, j <= n 。
行号,列号都从1开始。
【输出格式】
一行。一个正整数,即题目中所说最小的 k 。【样例输入】
5
3 1
1 2
4 4
2 3
5 5【样例输出】
3【数据范围】
对于 30% 的数据满足 n <= 10
对于 60% 的数据答案不超过 10^18
对于 100% 的数据满足 n <= 10000资源约定:
峰值内存消耗(含虚拟机) < 256M
CPU消耗 < 1000ms请严格按要求输出,不要画蛇添足地打印类似:“请您输入…” 的多余内容。
所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意:不要使用package语句。不要使用jdk1.7及以上版本的特性。
注意:主类的名字必须是:Main,否则按无效代码处理。
感觉是道数学规律题,但是我只会暴力骗小数据的分,(流下了线代差的泪水.jpg)后面想到更好的方法再更。
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;
public class G201405 {
static StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
static PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
static int[][] mar,tem;
static int n,u,v;
static int[][] quickpow(int x){
x--;
int[][] res = mar.clone();
int[][] m = mar.clone();
while(x != 0){
if((x&1) != 0) res = mul(res, m);
m = mul(m, m);
x = x >> 1;
}
return res;
}
static int[][] mul (int[][] a, int[][] b){
int[][] res = new int[n+1][n+1];
for(int i = 1; i<=n; i++){
for(int j = 1; j<=n; j++){
for(int k = 1; k<=n; k++){
res[i][j] += a[i][k]*b[k][j];
}
}
}
return res;
}
static boolean check(){
for(int i = 1; i<=n; i++){
for(int j = 1; j<=n; j++){
if(i == j){
if(tem[i][j] != 1) return false;
}
else {
if(tem[i][j] == 1) return false;
}
}
}
return true;
}
public static void main(String[] args) throws IOException{
in.nextToken();
n = (int)in.nval;
mar = new int[n+1][n+1];
tem = new int[n+1][n+1];
for(int i = 0; i<n; i++){
in.nextToken();
u = (int)in.nval;
in.nextToken();
v = (int)in.nval;
mar[u][v] = 1;
}
for(int i = 0; i<(int)1e9; i++){
if(i == 0) tem = mar;
else tem = quickpow(i);
if(check()){
out.println(i);
out.flush();
break;
}
}
}
}