(PS:今天搞octopress搞了一天,还是没有搞定,到了9点半实在不行了,就暂时放弃了。。。)
这次的题目,怎么说呢,用“只有你想不到的,没有你做不到。”的来形容实在是再好不过了。
A( BOJ 413 学姐的桌面)很水的一题,不过有些坑。
题意大概是,学姐偷到了360内部的用户开机时间的数据,给了你学姐的开机时间和偷到的所有n个用户的开机时间,问你学姐的开机时间比多少用户快;
坑就坑在那个开机时间上,谁知道他的开机时间竟然是越大越快!!不小心看测试数据的话,就会掉进坑里。代码如下
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#define N 100005
using namespace std;
int a[N];
int main()
{
int T;
cin>>T;
while (T--)
{
memset(a,0,sizeof(0));
int n,t;
int cnt=0;
scanf("%d%d",&n,&t);
for (int i=1;i<=n;i++)
{
int m;
scanf("%d",&m);
if (t>m) cnt++;
}
double ans=((double)cnt/n)*100.00;
printf("%.2lf",ans);
cout<<"%"<<endl;
}
}
B(BOJ0414 学姐去学车)一个逻辑问题,逻辑理清楚了就简单了
题意是,学姐去学车,有两个教练轮流教,这两个教练都是连续上班n天之后放一天的假,当前教学姐的教练放假后,换另外一个教练,一直教到这个教练放假,再换回原来那个教练。教练1从第1天开始教学姐(当做之前一天刚放完假),教练2第m天放假(1<=m<=n),问你第day天是哪个教练教学姐。(数据是1e9以内)
很容易就发现,因为教练的放假时间和上班时间是相同的,所以这肯定是一个循环的问题。循环节是多少呢?每个教练上班n天,然后再放假1天,很明显,循环节应该是(n+1)所以,我们可以列一下每个教练放假的时间,
教练1 教练2 根据左边,很容易 教练1 教练2
0 m 知道教练的上班时 [1,n] [n+1,n+m]
n+1 n+1+m 间 [n+m+1,2n+1] [2n+2,2n+1+m]
2n+2 2n+2+m [2n+2+m,3n+2] [3n+3,3n+2+m]
3n+3 3n+3+m . .
. . . .
右边的区间对n+1取余,就会发现,除了第一个区间,都有教练1[m,n] 教练2 [0,m-1]
综上,很容易得出结果,下面附代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#define N 100005
using namespace std;
int main()
{
int t;
cin>>t;
while (t--)
{
int n,m;
int coatch=1;
scanf("%d%d",&n,&m);
int q;
scanf("%d",&q);
for (int i=1;i<=q;i++)
{
int day;
scanf("%d",&day);
if (day==0) coatch=2;
else if (day>=1&&day<=n) coatch=1;
else
{
int mod=day%(n+1);
if (mod>=0&&mod<m) coatch=2;
else coatch=1;
}
printf("%d\n",coatch);
}
}
}
C(boj 0415 学姐的学弟)忽略了一个条件,就把简单题编程难题了。
题意是给你n个单位圆的坐标(为整点且大于1小于100),求这n个单位圆的总面积。
做题中自动忽略了坐标都是整数这个东西,结果。。。你懂得。
由于坐标都是整数,所以对于每一个单元格,都只有4中情况,空,满,1/4圆 和 2个弧分别过彼此圆心的 1/4圆。只要把这四种状态的面积求出来,然后对每个单元格进行判断求和即可
继续附代码
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <iostream>
#include <vector>
#include <algorithm>
#define pi 3.141592653
using namespace std;
int main()
{
double s=(pi/3.0)*2.0-sqrt(3.0)*0.5,s1=pi/2-s/2,s2=1.0,s3=pi/4;
int t;
int dx[]={1,1,0,0},dy[]={0,1,0,1};
cin>>t;
while (t--)
{
bool judge[105][105]={false};
int maxx=0,maxy=0,minx=105,miny=105;
int n;
double ans=0;
scanf("%d",&n);
for (int i=1;i<=n;i++)
{
int x,y;
scanf("%d%d",&x,&y);
judge[x][y]=true;
maxx=max(maxx,x+1);
maxy=max(maxy,y+1);
minx=min(minx,x-1);
miny=min(miny,y-1);
}
for (int i=minx;i<maxx;i++)
for (int j=miny;j<maxy;j++)
{
int pointNum=0;
for (int k=0;k<4;k++)
if (judge[i+dx[k]][j+dy[k]]) pointNum++;
if (pointNum>=3) ans+=s2;
else if(pointNum==1) ans+=s3;
else if(pointNum==2)
{
if (judge[i][j]&&judge[i+1][j+1]||judge[i][j+1]&&judge[i+1][j])
ans+=s2;
else ans+=s1;
}
}
printf("%.5lf\n",ans);
}
}
D(BOJ 407 BLOCKS) 一个搜索题,题意如下
给定一个n*m的矩阵,求问里面有多少个由'#'组成的矩形,若是里面有一个不是矩形的联通块,则输出"So Sad",数据时1000以内的.
时间上来说,搜索过是绰绰有余的。不过要注意一点,这个数据如果裸dfs的话,会堆栈溢出(1000*1000层)。
我用的是DFS,优化了下,思路如下。
找出每一块#区域的横纵坐标最大值和最小值(不管a[maxx,maxy] ,a[minx,miny]是否也是#);然后再在每个记录的区域内搜索,如果碰到不是#的,结果就应该是So Sad; 如果所有的#区域中都只有#,就输出#区域的个数。
DFS的剪枝是,只搜索每个#区域的边界(向外扩散),不用搜索内部(但是需要标记内部),因为我的搜索要记录的只是#区域的最大最小横纵坐标,所以可以这样做(内部的坐标肯定大于或者小于外部的),具体实现我就不赘述了,看代码应该能看懂吧!
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <map>
#define N 1005
using namespace std;
struct data
{
int maxx;
int maxy;
int minx;
int miny;
};
char board[N][N];
vector <data> rec;
vector <pair<int,int> > jingRec;
int n,m;
int dx[]={0,1,0,-1};
int dy[]={1,0,-1,0};
bool haveSearch[N][N];
void dfs(int x,int y,bool judge)
{
if (x<0||y<0||x>=n||y>=m) return;
if(haveSearch[x][y]) return;
haveSearch[x][y]=true;
if (judge) rec.push_back({x,y,x,y});
int sz=rec.size()-1;
int xx=x,yy=y;
while (board[xx+1][y]=='#')
{
xx++;
haveSearch[xx][y]=true;
}
while (board[x][yy+1]=='#')
{
yy++;
haveSearch[x][yy]=true;
}
if (rec[sz].maxx<xx) rec[sz].maxx=xx;
if (rec[sz].minx>x) rec[sz].minx=x;
if (rec[sz].maxy<yy) rec[sz].maxy=yy;
if (rec[sz].miny>y) rec[sz].miny=y;
for (int i=x;i<=xx;i++)
{
if (board[i][y-1]=='#') dfs(i,y-1,false);
if (board[i][yy+1]=='#') dfs(i,yy+1,false);
}
for (int i=y;i<=yy;i++)
{
if (board[x-1][i]=='#') dfs(x-1,i,false);
if (board[xx+1][i]=='#')dfs(xx+1,i,false);
}
}
int main()
{
while (~scanf("%d%d",&n,&m))
{
bool judge=false;
memset(board,0,sizeof(board));
memset(haveSearch,false,sizeof(haveSearch));
jingRec.clear();
rec.clear();
for (int i=0;i<n;i++)
{
scanf("%s",board[i]);
for (int j=0;j<m;j++)
if (board[i][j]=='#') jingRec.push_back({i,j});
}
for (int i=0;i<jingRec.size();i++)
{
bool needRec=!haveSearch[jingRec[i].first][jingRec[i].second];
dfs(jingRec[i].first,jingRec[i].second,true);
if (needRec)
{
int k=rec.size()-1;
for (int i=rec[k].minx;i<=rec[k].maxx;i++)
for (int j=rec[k].miny;j<=rec[k].maxy;j++)
haveSearch[i][j]=true;
}
}
for (int k=0;k<rec.size();k++)
{
if (judge) break;
for (int i=rec[k].minx;i<=rec[k].maxx;i++)
for (int j=rec[k].miny;j<=rec[k].maxy;j++)
if (board[i][j]!='#')
{
judge=true;
break;
}
}
if (judge) printf("So Sad\n");
else printf("There are %d ships.\n",rec.size());
}
}
E题,由于C++的大数敲起来太麻烦了,虽然找了个模板,但是也不想用了,打算近一个星期吧,抽些时间学学Java,然后再找几道大数的题练一练。
关于这题的题解,一种思路可以去参考下syx童鞋的这个博客,他那里还提到了另外一个博客,博主叫fisher_jiang(题目链接请点名字),那里有题目的描述和解题方法,我的思路跟他的差不多(当然,是有漏洞的,看了他的题解以后才明白错在哪里了),这个题的题解我也就不写了。