zznu组队赛⑧
论如何优雅地暴力?
Problem A:
题意:ZCC在玩一个游戏, 在这个游戏中他有一个技能,可以把一张牌变成他想要的样子. 现在给出5张牌,问ZCC至少需要多少次可以把5张牌变成同花顺. (A,B,C,D分别表示4种花色的牌,每种花色有1,2,3,4....13), 同花顺首先花色必须相同,然后花色后面的数字必须依次递增
比如1,2,3,4,5 10,11,12,13,1 都被看成顺子,而11,12,13,1,2 则不是.
没什么技巧, 暴力枚举
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<queue> #include<algorithm> #include<cmath> #include<iostream> using namespace std; typedef long long LL; #define oo 1000000007 #define mod 1000000007 #define maxn 205 int maps[maxn][maxn]; void get(char s[]) { int x = s[0]-'A'+1; int y = 0; for(int i = 1; s[i]; i++) y = y*10+s[i]-'0'; maps[x][y] = 1; } //maps[i][j](1<=i<=4 && 1<=j<=13) i表示花色 int main() { char s[maxn]; int T, i, j, n, ans, sum; scanf("%d", &T); while(T--) { ans = 100; n = 5; memset(maps, 0, sizeof(maps)); for(i = 1;i <= 5; i++) { scanf("%s", s); get(s); //标记该花色的牌 } for(i = 1; i<= 4; i++)//枚举花色 { for(j = 1; j <= 10; j++)//枚举顺子起始位置 { int t = j, cnt=0, sum=0; while(cnt < 5) { if(t > 13) t %= 13; if(maps[i][t]==0) sum++; cnt++; t++; } ans = min(ans, sum); } } printf("%d\n", ans); } return 0; }
Problem C:
硬币兑换,由递推的感觉.
首先考虑全部兑换成一种硬币的情况 1分的有1种 2分的有n/2种 3分的有n/3种, 然后考虑3种硬币混合的情况,枚举要兑换3分的个数相加即可. 如果兑换i(1<=i<=n/3)个3分的 那么就可以兑换2分的硬币(n-3*i)/2个,余下的补上一分的即可.
int i, n, ans, k; while(scanf("%d", &n) != EOF) { k = n/3; ans = 1+n/3+n/2;//全部由一种硬币组成的情况 for(i = 1; i <= k; i++)//有i个3分硬币,余下的兑换成2分的,不足的用一分的补齐. ans += (n-3*i)/2; printf("%d\n", ans); }
Problem D:
n个人坐成一圈,每个人手中有一定数量的糖果(糖果数量为偶数),现在做一个游戏,每当老师吹一次哨,左边的人把手中的糖的一半分给他右边的人, 如果某个人手中的糖果是奇数个的话,老师就再分给他一个糖果,
问经过多少次吹哨,所有人手中的糖果数量都相同.输出吹哨的次数,以及最后每个人手中的糖果的数量. 题目貌似没有太清晰的数据范围,不过这道题暴力可以过. 代码略丑,大家凑合着看吧
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<queue> #include<algorithm> #include<cmath> #include<iostream> using namespace std; typedef long long LL; #define oo 1000000007 #define mod 1000000007 #define maxn 205 int candys[1005], n; int judge() { int i; for(i = 1; i < n; i++) if(candys[i] != candys[i-1]) return 0; return candys[0]; } int main() { int i, t, ans, s, last; while(scanf("%d", &n), n) { ans = s = 0; for(i=0; i < n; i++) scanf("%d", &candys[i]); while(!ans) { s++; last = candys[0]; for(i = 1; i < n; i++) { t = candys[i]; candys[i] = t/2 + last/2; if(candys[i]%2) candys[i]++; last = t; } candys[0] = candys[0]/2+last/2; if(candys[0]%2) candys[0]++; ans = judge(); if(ans != 0) break; } printf("%d %d\n", s, ans); } return 0; }
Problem E:
这道题就是本次题目的坑点所在了, 关于题意就是判断一个数是否在给定的区间之内, A掉本题是需要脑洞的, 也是佩服出题人 ,真心不容易,,,
题意就不过多描述了,详细看代码
坑点:比如 空串, 再比如只包含'-'的串? 再比如 -0? 等等等等,,就不一一枚举了.
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<queue> #include<algorithm> #include<cmath> #include<iostream> using namespace std; typedef long long LL; #define oo 1000000007 #define mod 1000000007 #define maxn 205 char s[maxn]; int judge(int mark) {//mark 标记是否有 '-' 0表示没有,1表示有 int i =0, j, len=strlen(s); if(mark == 1) i ++; if(mark && len==1) return 0; //只由一个负号非法 if(s[i] == '0') return 0;//有前导0 非法 if(len == 0 || len > 15) return 0;//字符串为空串或者长度太长 非法 for(j = i; s[j]; j++) { if(s[j] >= '0' && s[j] <= '9') continue; return 0; //包含非数字字符 非法 } return 1; } int main() { int i, mark, legal, ok, a, b; LL suk;//计算合法的串的结果 while(gets(s) != 0) { scanf("%d %d%*c", &a, &b); ok = suk = mark = legal = 0; if(s[0] == '-') mark = 1; legal = judge(mark);//1 表示合法,0表示非法 if(legal)//合法的字符串参与 计算 { i = 0; if(mark) i = 1; for(; s[i]; i++) suk = suk*10+s[i]-'0'; if(mark) suk *= -1; if(suk >= a && suk <= b) ok = 1; } int len = strlen(s); if (len == 1 && s[0] == '0' && 0 >= a && 0 <= b) ok = 1;//只有1个0的情况也属合法的 if(ok) puts("YES"); else puts("NO"); } return 0; }
Problem F:题意:YJC 买了个表但是他不会读 他会给你一个时针与分针的角度(这个角度是乘12000之后的角度)并且他不想时间太精确秒数以10计数算出这个角度可能的时间点(时间 from 00:00:00 to 11:59:59)
时针每分钟转1/2度 -- 每秒钟转1/120度
分针每分钟转6度 每秒钟转1/10度
const int Round = 360*12000; int main() { int i, j, k, h, m, s, n; while(scanf("%d", &n)!=EOF) { for(i = 0; i < 12; i++) { for(j = 0; j < 60; j++) { for(k = 0; k < 60; k+= 10) { h = (i*3600+j*60+k)*100; m = (j*60+k)*1200; s = abs(h-m);//计算角度差 if(s > Round/2) s = Round-s; //时针与分针的角度定义为较小的夹角 if(s == n) printf("%02d:%02d:%02d\n", i, j, k); } } } } return 0; }
Problem G:
有一个n*n的地图, 这个图是在水上飘着的?(不要问为什么,) 你可以在地图上的某一个具体位置放上一些 石头? 然后这个位置就成陆地了? (英语较渣,不过大致就是这个意思,能做题,) 现在问你能不能将一个地图分割成k块陆地, (对于一块陆地的定义,地图的某个位置如果放有石头, 以及其上下左右四个方向上所有连通的是石头的格子 构成一块陆地, 即不同块的陆地之间必须有水隔着). 如果可以分割,输出任意一种方案即可.
解决方法:暴力枚举, 给地图的格子标号为 对应的行与列的和 即 i+j 如果是偶数 就放上一块石头, 观察是否放够k个(注意k==0的情况).(L代表石头, R代表是水)
/*例如: LL LL LL RL 这2个2*2的图 只包含一块陆地 LR RL 这2个2*2的图包含了2块陆地 */ #include<cstdio> #include<cstring> #include<stack> #include<queue> #include<cmath> #include<cstdlib> #include<iostream> #include<algorithm> using namespace std; const int oo = 1e9+7; const int maxn = 1e6+1e5; typedef long long LL; int maps[105][105]; int main() { int n, k, cnt, i, j, ok; while(scanf("%d %d", &n, &k) != EOF) { cnt = k; ok = 0; if(k==0) ok = 1; memset(maps, 0, sizeof(maps)); for(i = 0; i < n && !ok; i++) { for(j = 0; j < n && !ok; j++) { if((i+j)%2==0) { cnt--; maps[i][j] = 1; if(cnt == 0) { ok = 1; break; } } } } if(ok) { puts("YES"); for(i = 0; i < n; i++) { for(j = 0; j < n; j++) { if(maps[i][j]) printf("L"); else printf("S"); } puts(""); } } else puts("NO"); } return 0; }