A - LCM Challenge
Time Limit: 2000/1000MS (Java/Others) Memory Limit: 128000/64000KB (Java/Others)
Submit Status
Problem Description
Some days ago, I learned the concept of LCM (least common multiple). I’ve played with it for several times and I want to make a big number with it.
But I also don’t want to use many numbers, so I’ll choose three positive integers (they don’t have to be distinct) which are not greater than n. Can you help me to find the maximum possible least common multiple of these three integers?
Input
The first line contains an integer n (1 ≤ n ≤ 10^6) — the n mentioned in the statement.
Output
Print a single integer — the maximum possible LCM of three not necessarily distinct positive integers that are not greater than n.
Sample Input
9
Sample Output
504
解题思路:这题乍看挺水的,其实是很坑的一题。
首先想到的最大的肯定是(n) * (n-1) * (n-2),但是偶数的情况下并不是这样的,因为n和n-2会有公因子2所以,这种情况只适合奇数
现在考虑一下偶数,一般会想到n*(n-1) * (n-3)这是对的,但是少考虑到了一种情况,这个偶数能被3整数的情况,那样n和n-3就有公因子3了,所以这种情况也要考虑到
#include<cstdio>
#include<cstring>
int main() {
long long ans, n;
while(scanf("%lld", &n) != EOF) {
if(n == 1) {
printf("1\n");
}
else if(n == 2) {
printf("2\n");
}
else if(n == 3) {
printf("6\n");
}
else if(n % 2) {
ans = n * (n - 1) * (n - 2);
printf("%lld\n", ans);
}
else if(n % 3 == 0) {
ans = (n - 1) * (n - 2) * (n - 3);
printf("%lld\n", ans);
}
else {
ans = n * (n - 1) * (n - 3);
printf("%lld\n",ans);
}
}
return 0;
}
B - 瑶瑶带你玩激光坦克
Time Limit: 2000/1000MS (Java/Others) Memory Limit: 256000/128000KB (Java/Others)
Submit Status
Problem Description
有一款名为激光坦克的游戏,游戏规则是用一个坦克发出激光来达到一些目的,激光可以通过一些镜子反射。
机智的瑶瑶为了显示自己的智商高于常人,把这个游戏改造了一下,变成了用激光攻击敌人的游戏。
瑶瑶想知道射一次激光最多可以攻击到多少个敌人。
PS: 由于激光很强大,可以在击中敌人后穿过它,而瑶瑶自己的坦克由于有特殊装置,所以不会被激光击中,激光也会直接穿过它
Input
第1行两个正整数n, m (1 ≤ n, m ≤ 1000)表示地图大小,接下来n行每行m个字符描述地图。
. 表示此处为空地
* 表示此处为障碍(激光不可穿过,激光路径打到障碍时就结束)
T 代表瑶瑶的坦克位置
E 代表敌人
/ 代表按 左下-右上 放置的镜子
\ 代表按 左上-右下 放置的镜子
Output
一个整数代表瑶瑶向某个方向发射激光后最多可以攻击到的敌人数。
Sample Input
5 5
.*/E\
E*.*.
E*TEE
…/
.*\EE
Sample Output
4
解题思路:纯暴力,注意敌人来回被消灭两次的情况只能算一次,递归会re
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define maxn 1010
int n, m, g[maxn][maxn], vis[maxn][maxn][5], ans;
char str[maxn];
int dir[4][2] = {{-1,0},{1,0},{0,-1},{0,1}};
void dfs(int x, int y,int d, int cur) {
int xx = x, yy = y;
while(1) {
xx = xx + dir[d][0];
yy = yy + dir[d][1];
if(xx < 0 || xx >= n || yy < 0 || yy >= m || g[xx][yy] == 0 || vis[xx][yy][d] == cur)
return;
vis[xx][yy][d] = cur;
if(g[xx][yy] == 4 && vis[xx][yy][4] != cur) {
ans++;
vis[xx][yy][4] = cur;
}
if(g[xx][yy] == 1)
d = 3 - d;
if(g[xx][yy] == 2)
d = (d + 2) % 4;
}
}
int main() {
while(scanf("%d%d", &n, &m) == 2) {
int startx, starty;
for(int i = 0; i < n; i++) {
scanf("%s", str);
for(int j = 0; j < m; j++) {
vis[i][j][0] = vis[i][j][1] = vis[i][j][2] = vis[i][j][3] = vis[i][j][4] = -1;
switch(str[j]) {
case '\\':g[i][j] = 2;break;
case '/': g[i][j] = 1;break;
case '.': g[i][j] = 3;break;
case '*': g[i][j] = 0;break;
case 'E': g[i][j] = 4;break;
case 'T': g[i][j] = 3; startx = i;starty = j;break;
}
}
}
int Max = -1;
for(int i = 0; i < 4; i++) {
ans = 0;
dfs(startx, starty,i,i);
Max = max(ans, Max);
}
printf("%d\n",Max);
}
return 0;
}
C - 小晴天老师系列——竖式乘法
Time Limit: 4000/2000MS (Java/Others) Memory Limit: 128000/64000KB (Java/Others)
Submit Status
Problem Description
小晴天是ACdream团队中最牛的老师之一,他最擅长数学运算~这天他翻开一本《AC is not a dream》杂志,发现最后一页有一道很经典的思维题,题目很简单,每个框填写一个数字,构成一个竖式,每个数的最高位不能为0,但是有一些数字被隐藏掉了,然后让你根据没有隐藏的数字填出隐藏的数字。
如下图:
然后小晴天二话不说,三下五除二就写出了答案:
然后小晴天就觉得这样的题目太简单了,于是问你是否有办法来求出一道题目有多少种不同的答案呢?(只要有一个方框有不同的数字即为不同的答案)
Input
多组数据,首先是一个整数t(t<=20),表示数据组数。
对于每组数据,用5行表示一个竖式,每行均为一个字符串,仅含有星号(*)与数字(‘0’~’9’)组成,其中星号表示空白
其中第一行为长度为3的字符串。
第二行为长度为2的字符串。
第三行为长度为4的字符串。
第四行为长度为3的字符串。
第五行为长度为5的字符串。
Output
对于每组数据,输出一个整数x,表示符合乘法竖式法则的填法的种类。
Sample Input
2
**
3384
846
4**
**
3384
846
Sample Output
2
1
解题思路:这题没想复杂的话其实很简单,枚举一下三位数的和两位数的,然后再进行判断就可以了
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
char str[6][10];
int len[6] = {3,2,4,3,5};
int ans;
bool judge(int n, int cur) {
int t;
for(int i = len[cur] - 1; i >= 0; i--) {
t = n % 10;
n = n / 10;
if((str[cur][i] != '*') && (str[cur][i] - '0' != t))
return true;
}
return false;
}
void solve() {
for(int i = 100; i < 1000; i++) {
if(judge(i,0))
continue;
for(int j = 10; j < 100; j++) {
if(i * j > 100000)
break;
if(judge(j,1))
continue;
int x = i * (j % 10);
if((x >= 10000) || (x < 1000) || judge(x,2))
continue;
int y = i * (j / 10);
if((y >= 1000) || (y < 100) || judge(y,3))
continue;
int z = x + y * 10;
if( (z < 100000) && (z >= 10000) && !judge(z,4))
ans++;
}
}
}
int main() {
int test;
scanf("%d", &test);
while(test--) {
for(int i = 0; i < 5; i++)
scanf("%s", str[i]);
ans = 0;
solve();
printf("%d\n", ans);
}
return 0;
}
D - 小晴天老师系列——晴天的后花园
Time Limit: 10000/5000MS (Java/Others) Memory Limit: 128000/64000KB (Java/Others)
Submit Status
Problem Description
小晴天非常漂亮的后花园,打算以后退休之后在里面种种花,养养草,所以现在小晴天打算为他的后花园围上栅栏。
小晴天的后花园可以看成是一个m*n的矩形,但是其中有一些地方种了树,这些地方都不能安装栅栏,现在小晴天把后花园的平面图告诉你了,请你帮忙设计一个最大的矩形栅栏。
Input
单组数据,第一行包括两个整数m,n(1<=m,n<=500),接下来m行,每行包括n个字符,仅由’x’和’.’组成(ASCII码分别是120与46).
其中‘x’表示这个方格有树木,‘.’表示这个点可以建造栅栏
Output
若可以围成一个闭合栅栏,输出一个整数,表示栅栏能打到的最大周长
否则输出impossible
Sample Input
4 5
…..
.x.x.
…..
…..
2 2
.x
x.
2 5
…..
xxxx.
Sample Output
解题思路:先计算一下每个点所能延长的最右端和最下端是哪里,然后进行暴力
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define maxn 510
int right[maxn][maxn], down[maxn][maxn], n, m;
char str[maxn][maxn];
void init() {
for(int i = 0; i < n; i++)
for(int j = 0; j < m; j++) {
if(str[i][j] == 'x') {
right[i][j] = down[i][j] = -1;
continue;
}
if(!i || str[i-1][j] == 'x') {
int k;
for(k = i; k < n; k++)
if(str[k][j] == 'x')
break;
down[i][j] = k - 1;
}
else
down[i][j] = down[i-1][j];
if(!j || str[i][j-1] == 'x') {
int k;
for(k = j; k < m; k++)
if(str[i][k] == 'x')
break;
right[i][j] = k - 1;
}
else
right[i][j] = right[i][j-1];
}
}
void solve() {
int ans = 0;
for(int i = 0; i < n; i++)
for(int j = 0; j < m; j++) {
if(str[i][j] == 'x')
continue;
int len = 0, t;
for(int r = right[i][j]; r > j; r--)
for(int d = down[i][j]; d > i; d--) {
if(down[i][r] >= d && right[d][j] >= r) {
t = 2 * (r - j + d - i);
len = max(len, t);
}
}
ans = max(len,ans);
}
if(ans == 0)
printf("impossible\n");
else
printf("%d\n", ans);
}
int main() {
while(scanf("%d%d",&n, &m) == 2) {
for(int i = 0; i < n; i++)
scanf("%s",str[i]);
init();
solve();
}
return 0;
}
E - 小晴天老师系列——我有一个数列!
Time Limit: 20000/10000MS (Java/Others) Memory Limit: 128000/64000KB (Java/Others)
Submit Status
Problem Description
小晴天:“我有一个数列!”
小晴天:“我还要有很多很多的数列!”
于是小晴天就把这个数列的所有连续子数列写出来。
然后小晴天把每个连续子数列中的最大的数写出来。
那么,有多少个比K大呢?
Input
多组数据,首先是一个正整数t(t<=100),表示数据的组数
对于每组数据,首先是两个整数n(1<=n<=200000),K(0<=K<=10^9).,但所有数据中的n之和不超过1000000.
接下来是n个整数ai
Output
对于每组数据,输出一个整数,表示最大元素大于K的连续子序列的个数。
Sample Input
2
3 2
1 2 3
3 1
1 2 3
Sample Output
这题好水:
用一个数组纪录以该数字为最后一个数所符合的子序列有多少个,然后进行统计即可,
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define maxn 200010
int dp[maxn], num[maxn];
int main() {
int test, n, k, t;
scanf("%d", &test);
while(test--) {
long long ans = 0;
scanf("%d%d", &n ,&k);
scanf("%d", &t);
if(t > k) {
ans = dp[0] = 1;
}
else {
ans = dp[0] = 0;
}
for(int i = 1; i < n; i++){
scanf("%d", &t);
if(t > k)
dp[i] = i + 1;
else
dp[i] = dp[i-1];
ans += dp[i];
}
printf("%lld\n", ans);
}
return 0;
}
F - 小晴天老师系列——苹果大丰收
Time Limit: 2000/1000MS (Java/Others) Memory Limit: 128000/64000KB (Java/Others)
Submit Status
Problem Description
小晴天的后花园有好多好多的苹果树,某天,苹果大丰收~小晴天总共摘了M个苹果,我们假设苹果之间是不可分辨的。
为了保存苹果,小晴天买了N个一模一样的箱子,想要把苹果放进去,允许有的箱子是空的,请问小晴天有多少种不同的放法呢?
例如对于4个苹果,3个箱子,2+1+1和1+2+1和1+1+2 是同一种分法。
Input
多组数据,首先是一个正整数t(t<=100)表示数据的组数。
每组数据均包含二个整数M和N(1<=M,N<=10)。
Output
对于每组数据,输出一个整数,表示不同的放法数。
Sample Input
1
7 3
Sample Output
水题,排序放入即可
#include<cstdio>
#include<cstring>
int ans, n, m;
void dfs(int cur, int box, int pre) {
if(box >= m) {
if(cur == 0)
ans++;
return;
}
for(int i = cur; i >= 0; i--)
if(i <= pre)
dfs(cur - i, box + 1, i);
}
int main() {
int test;
scanf("%d", &test);
while(test--) {
scanf("%d%d", &n, &m);
ans = 0;
dfs(n,0,n);
printf("%d\n",ans);
}
return 0;
}
G - 小晴天老师系列——可恶的墨水瓶
Time Limit: 2000/1000MS (Java/Others) Memory Limit: 128000/64000KB (Java/Others)
Submit Status
Problem Description
小晴天老师正在备课,这时,可恶的墨水瓶突然自己打翻了!悲剧发生了!小晴天的备课稿都被墨水弄脏了。。。。
不过小晴天很乐观~这时他把他的一张纸分成n*m个格子,其中有一些格子被墨水涂黑了,有的没有。那么小晴天想知道,最大的一块联通的墨水块占多少个格子呢?
所谓的联通的即两个格子至少有一个公共顶点。
Input
多组数据,首先是一个正整数t(t<=20)
对于每组数据,先给出两个整数m.n(1<=n,m<=20)
然后是一个m行n列的01矩阵,若为1,则该格子被墨水染黑。
Output
对于每组数据,输出一个整数,表示最大被墨水染黑的连通格子数。
Sample Input
1
4 4
1 1 0 0
0 1 1 0
0 0 1 0
1 0 0 0
Sample Output
解题思路:纯暴力
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define maxn 25
int g[maxn][maxn], vis[maxn][maxn];
int n, m;
int dir[8][2] = {{-1,-1},{-1,0},{-1,1},{0,-1},{0,1},{1,-1},{1,0},{1,1}};
int dfs(int x, int y) {
int cnt = 0;
for(int i = 0; i < 8; i++) {
int xx = dir[i][0] + x;
int yy = dir[i][1] + y;
if(xx >= 0 && xx < n && yy >= 0 && yy < m && g[xx][yy] && !vis[xx][yy]) {
vis[xx][yy] = 1;
cnt += dfs(xx,yy) + 1;
}
}
return cnt;
}
int main() {
int test;
scanf("%d", &test);
while(test--) {
scanf("%d%d", &n, &m);
memset(g,0,sizeof(g));
memset(vis,0,sizeof(vis));
for(int i = 0; i < n; i++)
for(int j = 0; j < m; j++)
scanf("%d", &g[i][j]);
int ans = 0, t;
for(int i = 0; i < n; i++)
for(int j = 0; j < m; j++)
if(!vis[i][j] && g[i][j]) {
vis[i][j] = 1;
t = dfs(i,j) + 1;
ans = max(t,ans);
}
printf("%d\n",ans);
}
return 0;
}