2018年的题感觉比前两年的难上一些,之前是有想法但错,这次是完全没想法,毕竟这次好像没dfs了。
1.第几天
手算或者打开Excel用函数
答案:125
2.明码
把对应的像素点标记为1,输出时有1就输出星号,没就输出空格。最后像素点问的是:“九的九次方等于多少?"
pow一下就好
答案:387420489
d
#include <iostream>
#include <cstring>
using namespace std;
int ziji[8];
int main()
{
int a;
for(int i=1;i<=10*32;i++)
{
memset(ziji,0,sizeof(ziji));
cin>>a;
for(int j=7;j>=0;j--)
{
ziji[j]=a&1;
a>>=1;
}
for(int j=0;j<=7;j++)
if(ziji[j]==1)
cout<<"*";
else cout<<" ";
if(i%2==0)
cout<<endl;
}
return 0;
}
3.乘积末尾有多少个零
0的来源是2×5。所以对每个数都不停地取2和5的因子,最后两者的较小值就是答案。
答案:31
#include <iostream>
#include <algorithm>
using namespace std;
int infor[10][10],all,ans[2];
int main()
{
int i,j;
for(i=0;i<10;i++)
for(j=0;j<10;j++)
cin>>infor[i][j];
for(i=0;i<10;i++)
for(j=0;j<10;j++)
while(infor[i][j]%2==0)//取2
{
infor[i][j]/=2;
ans[0]++;
}
for(i=0;i<10;i++)
for(j=0;j<10;j++)
while(infor[i][j]%5==0)//取5
{
infor[i][j]/=5;
ans[1]++;
}
all=min(ans[0],ans[1]);
cout<<all;
return 0;
}
4.测试次数
标题:测试次数
x星球的居民脾气不太好,但好在他们生气的时候唯一的异常举动是:摔手机。
各大厂商也就纷纷推出各种耐摔型手机。x星球的质监局规定了手机必须经过耐摔测试,并且评定出一个耐摔指数来,之后才允许上市流通。
x星球有很多高耸入云的高塔,刚好可以用来做耐摔测试。塔的每一层高度都是一样的,与地球上稍有不同的是,他们的第一层不是地面,而是相当于我们的2楼。
如果手机从第7层扔下去没摔坏,但第8层摔坏了,则手机耐摔指数=7。
特别地,如果手机从第1层扔下去就坏了,则耐摔指数=0。
如果到了塔的最高层第n层扔没摔坏,则耐摔指数=n
为了减少测试次数,从每个厂家抽样3部手机参加测试。
某次测试的塔高为1000层,如果我们总是采用最佳策略,在最坏的运气下最多需要测试多少次才能确定手机的耐摔指数呢?
请填写这个最多测试次数。
注意:需要填写的是一个整数,不要填写任何多余内容。
答案:19
一开始想二分,突然发现限制了手机数,玩完,不会。后来看题解,是动态规划,想不到,在这里就做一次解释并思考用动态规划的原因。
解:
假设i个手机共j层楼,如果在k层摔坏了,那么就是i-1个手机k-1层楼的情况;如果没坏,就是i个手机测k+1到j层的情况,此情况与i个手机测1到j-k层的情况等价(假设把层数减k,把抗摔能力也减k,消减并不会对结果产生影响,所以等价)。得出递推式:dp[i][j]=max(dp[i-1][k-1],dp[i][j-k])+1,k
∈
\in
∈[1,j-1](相当于把上述过程逆推)用max是因为要使得dp[i][j]满足所有情况,再做更新取最小:dp[i][j]=min(dp[i][j],max(dp[i-1][k-1],dp[i][j-k])+1)),k
∈
\in
∈[1,j-1]。
一开始初始化为最坏情况,j层楼为j次。
#include <iostream>
#include <algorithm>
using namespace std;
int dp[4][1010],i,j,k;
int main()
{
for(i=1;i<=3;i++)
for(j=1;j<=1000;j++)
dp[i][j]=j;//所有的最坏情况
for(i=2;i<=3;i++)
for(j=1;j<=1000;j++)
for(k=1;k<j;k++)
dp[i][j]=min(dp[i][j],max(dp[i-1][k-1],dp[i][j-k])+1);
cout<<dp[3][1000];
return 0;
}
代码十分简洁。
转一下动态规划问题的特点:
此类问题具有的特点:
【1】问题的目标是求一个问题的最优解;
【2】整体问题的最优解依赖于各个子问题的最优解;
【3】把大问题分解成若干个小问题,这些小问题之间还有相互重叠的更小的子问题;
【4】从上往下分析问题,从下往上解决问题。
5.快速排序
又烂了
答案:a,i+1,r,k-(i-l+1)
6.递增三元组
**思路:**要找满足Ai < Bj < Ck的数据,显然暴力是过不去的 。那么关于搜索,可以用二分来实现,而二分要求有序,即要先排序,sort实现。,具体写法是以为B中心,向A和C搜索,分别搜索小于此时的B和大于此时B的值的数量
#include <iostream>
#include <algorithm>
#define MAX 100005
using namespace std;
int a[MAX],b[MAX],c[MAX];
int main()
{
int n;
cin>>n;
for(int i=0;i<n;i++)
cin>>a[i];
for(int i=0;i<n;i++)
cin>>b[i];
for(int i=0;i<n;i++)
cin>>c[i];
sort(a,a+n);
sort(b,b+n);
sort(c,c+n);//排序用于二分
int sum=0;
for(int i=0;i<n;i++)
{
int x=(lower_bound(a,a+n,b[i])-a); //大于等于此值的第一个,向前共多少个
int y=n-(upper_bound(c,c+n,b[i])-c); //大于此值的第一个,向后共多少个
sum+=x*y;//累计
}
cout<<sum<<endl;
return 0;
}
7.dis(x,y)
看似搜索,但是会爆,实则分块找规律,分块一般是靠y=x和y=-x两条线来分割,分割点要仔细考虑,其余的就是列表找规律了。
#include <iostream>
#include <cmath>
using namespace std;
int x,y;
int main()
{
cin>>x>>y;
if(y>=0&&abs(x)<=y) cout<<4*y*y+x-y;
else if(y<0&&abs(x)<=abs(y)) cout<<(-2*y+1)*(-2*y+1)-x+y-1;
else if(x>0&&abs(y)<x) cout<<4*x*x+x-y;
else if(x<0&&abs(y)<abs(x)) cout<<(-2*x-1)*(-2*x-1)-x+y-1;
return 0;
}
8.日志统计
小明维护着一个程序员论坛。现在他收集了一份”点赞”日志,日志共有N行。其中每一行的格式是:
ts id
表示在ts时刻编号id的帖子收到一个"赞"。
现在小明想统计有哪些帖子曾经是"热帖"。如果一个帖子曾在任意一个长度为D的时间段内收到不少于K个赞,小明就认为这个帖子曾是"热帖"。
具体来说,如果存在某个时刻T满足该帖在[T, T+D)这段时间内(注意是左闭右开区间)收到不少于K个赞,该帖就曾是"热帖"。
给定日志,请你帮助小明统计出所有曾是"热帖"的帖子编号。
【输入格式】
第一行包含三个整数N、D和K。
以下N行每行一条日志,包含两个整数ts和id。
对于50%的数据,1 <= K <= N <= 1000
对于100%的数据,1 <= K <= N <= 100000 0 <= ts <= 100000 0 <= id <= 100000
【输出格式】
按从小到大的顺序输出热帖id。每个id一行。
【输入样例】
7 10 2
0 1
0 10
10 10
10 1
9 1
100 3
100 3
【输出样例】
1
3
资源约定:
峰值内存消耗(含虚拟机) < 256M
CPU消耗 < 1000ms
解:
对每个id分别记录,防止消耗内存过大用vector,再对每个id分别判断,用尺取法(记录区间左右端点,不断推进右端点,满足条件时移动左端点,不满足再移动右端点,直到右端点到极限),不然应该会爆吧。
#include <iostream>
#include <vector>
#include <algorithm>
#define MAXN 100010
using namespace std;
int ans[MAXN],n,d,k,ts,id,all;
vector<int> infor[MAXN];
bool check(int a)
{
int i,sum=0,l=0,r=0,len=infor[a].size();
if(len<k) return false;
sort(infor[a].begin(),infor[a].end());
while(l<=r&&r<len)//尺取法
{
sum++;
if(sum>=k)
{
if(infor[a][r]-infor[a][l]<d)
return true;
else
{
l++;
sum--;
}
}
r++;
}
return false;
}
int main()
{
int i;
cin>>n>>d>>k;
for(i=0;i<n;i++)
{
cin>>ts>>id;
infor[id].push_back(ts);
}
for(i=1;i<=10000;i++)
if(check(i))
ans[all++]=i;
for(i=0;i<all;i++)
cout<<ans[i]<<endl;
return 0;
}
9.全球变暖
dfs完事
#include <iostream>
using namespace std;
char t;
int n,lef,all,dir[4][2]={1,0,-1,0,0,1,0,-1};
bool use1[1010][1010],use2[1010][1010],use3[1010][1010];
void dfs(int a,int b,bool (*c)[1010],bool (*d)[1010])//标记
{
d[a][b]=false;
int x,y,i;
for(i=0;i<4;i++)
{
x=a+dir[i][0];
y=b+dir[i][1];
if(x>=0&&x<n&&y>=0&&y<n&&c[x][y]&&d[x][y])
dfs(x,y,c,d);
}
}
bool check(int a,int b)//淹水
{
for(int i=0;i<4;i++)
{
int x=a+dir[i][0],y=b+dir[i][1];
if(!use1[x][y])
return false;
}
return true;
}
int main()
{
int i,j;
cin>>n;
for(i=0;i<n;i++)
for(j=0;j<n;j++)
{
cin>>t;
if(t=='#')
use1[i][j]=true;
use3[i][j]=use2[i][j]=use1[i][j];
}
for(i=0;i<n;i++)
for(j=0;j<n;j++)
if(use1[i][j]&&use2[i][j])
{
all++;//搜原有多少岛
dfs(i,j,use1,use2); //标记此岛
}
for(i=0;i<n;i++)
for(j=0;j<n;j++)
if(use/1[i][j])
use3[i][j]=check(i,j);//开淹
for(i=0;i<n;i++)
for(j=0;j<n;j++)
if(use3[i][j])
{
lef++;//剩余
dfs(i,j,use3,use3);//标记此岛
}
cout<<all-lef;//消失的数量
return 0;
}
10.乘积最大
**思路:**按绝对值大小排序:
1.如果前k个里有0,即后面都是0,那么只能取乘积最大只能为0;
2.如果前k个里负数的个数为偶数个,那就取前k个;
3.如果负数的个数为奇数个:
可以把前k个里最小的负数换成后面最大的正数或者把前k个里最小的正数换成后面最大的负数,比较哪种大,即可。
若其中一种不存在,直接取另一种;
若都凑不齐,看看后面有没有0,有0最大就是0,若没有,从后往前取k个,此时乘积是最大的负数。
#include <iostream>
#include <cmath>
#include <algorithm>
#define MAXN 1000000009
using namespace std;
typedef long long int ll;
ll infor[100010],n,k,z,f,o,sum=1;
bool comp(int a,int b)//按绝对值由大到小排序
{
return abs(a)>abs(b);
}
int main()
{
int i,j;
cin>>n>>k;
for(i=0;i<n;i++)
cin>>infor[i];
sort(infor,infor+n,comp);//按绝对值从大到小排
for(i=0;i<k;i++)
{
if(infor[i]>0) z++;//正的数
else if(infor[i]<0) f++;//负的
else o++;//0
}
if(o) sum=0;//前k个有0,只能是0
else if(f%2==0) //偶数个负数,前k个全用就最大
{
for(i=0;i<k;i++)
{
sum*=infor[i];
if(sum>0) sum%=MAXN;
else sum=0-(0-sum)%MAXN;//取余
}
}
else//奇数个负数
{
ll zxz=1000000,zxf=0,zdz=0,zdf=-1000000;//最小正数,最小负数,最大正数,最大负数(指绝对值)
for(i=0;i<k;i++)//在前k个里取最小负数、最小正数
{
if(infor[i]>=0) zxz=min(zxz,infor[i]);
else zxf=min(zxf,infor[i]);
}
for(i=k;i<n;i++)//在后续取最大正数、最大负数
{
if(infor[i]>=0) zdz=max(zdz,infor[i]);
else zdf=max(zdf,infor[i]);
}
if((zdz==0||zxf==0)&&(zdf==-1000000||zxz==1000000))//都找不全没法换
{
int flag=0;
for(i=0;i<n;i++)
if(infor[i]==0)
{
flag=1;
break;
}
if(flag) sum=0;//有0就为0
else//没有0,反正为负,就取小的,负的少一点
{
for(i=n-1,j=0;j<k;i--,j++)
{
sum*=infor[i];
if(sum>0) sum%=MAXN;
else sum=0-(0-sum)%MAXN;
}
}
}
else if((zdf==-1000000||zxz==1000000)||zdz*zxz>zdf*zxf)//没找到最小正数或最大负数或者替换最小负数时更大
{
int flag=0;
for(i=0;i<k;i++)
{
if(!flag&&infor[i]==zxf)//最小负不算进去
{
flag=1;
continue;
}
sum*=infor[i];
if(sum>0) sum%=MAXN;
else sum=0-(0-sum)%MAXN;
}
sum=sum*zdz%MAXN;
}
else if((zdz==0||zxf==0)||zdz*zxz<=zdf*zxf)//没找到最大正数或最小负数或替换最小正数时更大
{
int flag=0;
for(i=0;i<k;i++)
{
if(!flag&&infor[i]==zxz)
{
flag=1;
continue;
}
sum*=infor[i];
if(sum>0) sum%=MAXN;
else sum=0-(0-sum)%MAXN;
}
sum=sum*zdf%MAXN;
}
}
cout<<sum<<endl;
return 0;
}