A.Flipping Game
题目大意:输入一个数n , 然后输入n个数a1 , a2...an (ai = 0 或者 ai = 1 ,1 <= i <= n) ,接下来你需要进行一个操作:选定两个下标i 和 j ,使ai , ai + 1 ......aj 按如下规则变化:ak = 1 - ak (i <= k <= j)。要求经过这一步操作后,使这n个数中 1 的个数最多, 并输出这个最大值。此题,我原本以为是动态规划,就先做了后面的题,后来被队友告知直接暴力就可以,汗。。请看代码:
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<string> #include<cmath> #include<cstdlib> #include<queue> using namespace std ; int s[105] ; int s2[105] ; int main() { int n ; while (scanf("%d" , &n) != EOF) { int i , j ; for(i = 0 ; i < n ; i ++) { scanf("%d" , &s[i]) ; } int max = -1 ; for(i = 0 ; i < n ; i ++) { for(j = i ; j < n ; j ++) { for(int j3 = 0 ; j3 < n ; j3 ++) // 别忘每次都要初始化 { s2[j3] = s[j3] ; } int k ; for(k = i ; k <= j ; k ++) s2[k] = 1 - s2[k] ; int sum = 0 ; for(int j2 = 0 ; j2 < n ; j2 ++) { if(s2[j2] == 1) sum ++ ; } if(sum > max) { max = sum ; } } } printf("%d\n" , max) ; } return 0 ; }
题目大意:给你一个数n , 让你找出n 个数a1 , a2 ... an , 它们满足如下条件:a1 < a2 < a3 < ... < an , 并且对于任意的ai 和 aj (ai < aj), aj不能被ai 整除。任意一种满足条件的序列都可以。此题先用筛一下素数,然后,显然不同素数之间都是互质的,只要从小到大依次输出n个素数即可。请看代码:
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<string> #include<cmath> #include<cstdlib> #include<queue> using namespace std ; const int MAXN = 10000008 ; int s[MAXN] ; int n ; void prim() // 建立素数表 { int i ; s[0] = s[1] = 1 ; for(i = 2 ; i <= MAXN ; i ++) { int j ; if(s[i] == 0) for(j = 2 ; j * i <= MAXN ; j ++) { s[i * j] = 1 ; } } } int main() { memset(s , 0 , sizeof(s)) ; prim() ; while (scanf("%d" , & n) != EOF) { int i ; int j = 0 ; for(i = 2 ; ;) { if(s[i] == 0) { printf("%d" , i) ; j ++ ; if( j < n ) { printf(" ") ; } } i ++ ; if(j == n ) { printf("\n") ; break ; } } } return 0 ; }
C.Magic Five
这道题是一道找规律推公式的题,唯一的难度在于用到数论中的欧拉定理和求一个数a mod n 的乘法逆元,但是这个我现在还不能掌握,准备日后等真正理解了再好好写一写此题的结题报告。原本这个题在BNU上我用简单的方法A掉了,但在CF上确实超时,可能是BNU 的问题吧,下面先写一下我原先的代码:
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<string> #include<cmath> #include<cstdlib> #include<queue> using namespace std ; const int MAXN = 1e9 + 7; const int M = 1e6 + 5 ; char s[M] ; long long sum[M] ; long long mi(long long n) //快速幂 { if(n == 0) return 1 ; if(n == 1) return 2 ; if(n % 2 == 0) return ((mi(n / 2) % MAXN) * (mi(n / 2) % MAXN)) % MAXN ; else return (((mi(n / 2) % MAXN) * (mi(n / 2) % MAXN)) * 2 ) % MAXN ; } int main() { memset(s , 0 , sizeof(s)) ; memset(sum , 0 ,sizeof(sum)) ; while (scanf("%s" , s) != EOF) { int k ; scanf("%d" , &k) ; int len = strlen(s) ; int i ; int cnt = 0 ; for(i = 0 ; i < len ; i ++) { if(s[i] == '5' || s[i] == '0') { sum[cnt] = i ; cnt ++ ; } } long long ans = 0 ; int j ; for(i = 0 ; i < cnt ; i ++) { for(j = 0 ; j < k ; j ++) { ans = (ans + (mi((sum[i] + len * j)) % MAXN )) % MAXN ; } } printf("%lld" , ans) ; } return 0 ; }
D.Block Tower
题目大意:给你一个n * m 的矩形地图,地图中总共可能有两种符号: ‘.’ 和 ‘#’ ,‘.’ 表示空地, 能在这里建造房子,‘#’表示黑洞,不能在这里建造房子。能建造的房子共有两种:第一种是蓝色的房子,能容纳100 个 人 ;第二种是红色房子 , 能容纳200人,但是必须在蓝色房子旁边的空地才能建造。你能进行三种操作:一、建造蓝色房子 ,代号为“B”;二、建造红色房子,代号为“R”;三、摧毁建造的房子 ,代号为“D” 。现要求你在空地上建造房子,是能够容纳的人数最大,并输出你进行的操作的总步数和每步操作之行的内容,如:B 1 2 ,代表在点(1,2) 上建造蓝色房子。
解题思路:此题采用dfs , 找出相邻的‘.’所占的最大区域(与寻找魔方的最大色块有些相似) ,并在此过程中将所有符号为 ‘.’ 的点都建上蓝色的房子,当搜索进行完时 ,便进入回退的过程中,并在此过程中将所有的点(除搜索的其实点外)上面的蓝色房子摧毁,然后再建上红色的房子,这样当回退结束后,原先相邻的符号为 ‘.’ 的区域中除搜索的起始点是蓝色房子外,其他的点均为红色房子,这样就能使所容纳的人数最大,因为红色的房子必须在蓝色房子的旁边建造,所以一块相邻的符号为 ‘.’ 的区域中不可能将所有的点都建为红色房子 。下面请看代码:
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<string> #include<cmath> #include<cstdlib> #include<queue> using namespace std ; const int MAXN = 605 ; char map[MAXN][MAXN] ; int vis[MAXN][MAXN] ; int n , m ; int X[4] = {0 , 0 , 1 , -1} ; int Y[4] = {1 , -1 , 0 , 0} ; char clo[MAXN * MAXN * 10] ; // 注意:以下数组应开大一些,因为 //题目中要进行的操作会比较多,否则会WA int zx[MAXN * MAXN * 10] ; int zy[MAXN * MAXN * 10] ; int cango(int x , int y) { if( x >= 1 && x <= n && y >= 1 && y <= m && !vis[x][y] && map[x][y] == '.') return 1 ; return 0 ; } int cnt ;// 统计操作的步数 void dfs(int x , int y ) // 深搜 { vis[x][y] = 1 ; clo[cnt] = 'B' ; // 对于深搜到的每个点先建上蓝色房子 zx[cnt] = x ; // 记录当前位置坐标 zy[cnt] = y ; cnt ++ ; int k ; for(k = 0 ; k < 4 ; k ++) { int tx = x + X[k] ; int ty = y + Y[k] ; if(cango(tx , ty)) { vis[tx][ty] = 1 ; dfs(tx , ty) ; clo[cnt] = 'D' ; // 深搜回退时遇到这个点,先把 //原先建的蓝色房子摧毁,然后再建造红色房子 zx[cnt] = tx ; zy[cnt] = ty ; cnt ++ ; clo[cnt] = 'R' ; zx[cnt] = tx ; zy[cnt] = ty ; cnt ++ ; } } } int main() { while (scanf("%d%d" , &n , &m) != EOF) { memset(map , 0 , sizeof(map)) ; memset(vis , 0 , sizeof(vis)) ; memset(clo , 0 , sizeof(clo)) ; memset(zx , 0 , sizeof(zx)) ; memset(zy , 0 , sizeof(zy)) ; int i , j ; cnt = 0 ; for(i = 1 ; i <= n ; i ++) { for(j = 1 ; j <= m ; j ++) { cin >> map[i][j] ; } } for(i = 1 ; i <= n ; i ++) { for(j = 1 ; j <= m ; j ++) { if(map[i][j] == '.' && !vis[i][j]) { dfs(i , j) ; } } } printf("%d\n" , cnt) ; for(i = 0 ; i < cnt ; i ++) { printf("%c %d %d\n" , clo[i] , zx[i] , zy[i]) ; } } return 0 ; }