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 ;
}