这套题其实应该是个上分场的,然后第一次锁了之后被HACK了,然后A就错了,自己也觉得挺搞笑的
但是最终是个只出了B题的小垃圾
A:12小时和24小时的标准作息时间,12小时制的小时时间是1-12,24小时的是0-23,分钟都是0-59
现在给你一个时间,要求你改动最少的数字,让它变得合理
被hack的数据是:
12
20:00
我当时是没有单独考虑,不为0,而且被10整除的情况,我是直接对10取模的,所以就***错了
其实,就几类要改的情况:
当12小时制的时候,小时:0改成1,大于12的,如果被10整除改成10,否则,对10取模
当24小时制的时候,小时:0-23不变,其余的,对10取模
分钟与小时制无关,0-59不变,其余的对10取模
#include<bits/stdc++.h>
using namespace std;
int n,x,y;
int main(){
//freopen("input.txt","r",stdin);
while(scanf("%d",&n)!=EOF){
scanf("%d:%d",&x,&y);
if (n==12){
if (x==0) x=1;
else if (x>12){
if (x%10!=0) x=x%10;
else x=10;
}
}
else{
if (x>23) x=x%10;
}
if (y>59) y=y%10;
printf("%02d:%02d\n",x,y);
}
return 0;
}
B:题目中废话挺多的,其实就是数一数有几个“元音”字母:aeiouy
注意有一个Hack点,在比较的时候,只能用不等号来作为判断依据
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn=150;
const int maxl=150;
int n;
int p[maxn],a[maxn];
char s[maxl];
int main(){
//freopen("input.txt","r",stdin);
while(scanf("%d",&n)!=EOF){
for(int i=1;i<=n;i++) scanf("%d",&p[i]);
memset(a,0,sizeof(a));
bool flag=true;
getchar();
for(int i=1;i<=n;i++){
gets(s);
int len=strlen(s);
for(int j=0;j<len;j++)
if (s[j]=='a'||s[j]=='e'||s[j]=='i'||s[j]=='o'||s[j]=='u'||s[j]=='y') a[i]++;
if (a[i]!=p[i]) flag=false;
}
printf("%s\n",flag?"YES":"NO");
}
return 0;
}
C题是个很好的题:
有无数种方法可以过的:线段树+并查集+STL的set
并查集的搞法:维护每个区间的大小
#include<bits/stdc++.h>
using namespace std;
#define LL __int64
const int maxn=1e5+50;
LL a[maxn],ans[maxn];
int pos[maxn],n;
bool vis[maxn];
int fa[maxn];
int getfa(int x){
if (fa[x]==-1) return x;
return fa[x]=getfa(fa[x]);
}
void combine(int x,int y){
x=getfa(x);
y=getfa(y);
if (x!=y){
fa[x]=y;
a[y]+=a[x];
}
}
int main(){
//freopen("input.txt","r",stdin);
while(scanf("%d",&n)!=EOF){
for(int i=1;i<=n;i++) scanf("%I64d",&a[i]);
for(int i=1;i<=n;i++) scanf("%d",&pos[i]);
memset(vis,false,sizeof(vis));
memset(ans,0,sizeof(ans));
memset(fa,-1,sizeof(fa));
LL temp=0;
for(int i=n;i>=1;i--){
ans[i]=temp;
int x=pos[i];
vis[x]=true;
if (vis[x-1]) combine(x-1,x);
if (vis[x+1]) combine(x+1,x);
temp=max(temp,a[getfa(x)]);
}
for(int i=1;i<=n;i++)
cout<<ans[i]<<endl;
}
return 0;
}
set的搞法:
单纯的模拟:当前对分隔数组的影响:其实是对前缀和的分隔
我只需要找到离我最近的两次分割,我再来分隔一次就好
第一个set:保存当前已经分了哪些地方
第二个set:当前分隔之后的各个区间段的值是多少
之所以要用multiset:是因为可能会有重复的区间和值
#include<bits/stdc++.h>
using namespace std;
#define LL __int64
const int maxn=1e5+50;
int n,x;
LL a[maxn],L,R;
multiset<LL> s,res;
multiset<LL>::iterator it;
int main(){
//freopen("input.txt","r",stdin);
while(scanf("%d",&n)!=EOF){
s.clear();res.clear();a[0]=0;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
a[i]+=a[i-1];
}
a[n+1]=a[n];
res.insert(a[n]);
s.insert(0);s.insert(n+1);
for(int i=1;i<=n;i++){
scanf("%d",&x);
it=s.lower_bound(x);
R=*it;
it--;
L=*it;
s.insert(x);
res.erase(res.find(a[R-1]-a[L]));
res.insert(a[x-1]-a[L]);
res.insert(a[R-1]-a[x]);
cout<<*--res.end()<<endl;
}
}
return 0;
}
再来个线段树题解的链接:
D:一个数学思维的好题
因为集合中元素是固定的,所以一定是一对一的产生的
如果x能够产生y,按照题目中的规则,必有y/2==x成立
那么,我们可以二分答案(最大值的数是多少)
然后集合中的每个值不断除2,既不能为0,也不能重复,如果能够找到的话,就是个可能性的答案
#include<bits/stdc++.h>
using namespace std;
const int maxn=5e4+50;
int a[maxn],tmp[maxn],ans[maxn];
map<int,bool> vis;
int n;
bool check(int x){
vis.clear();
for(int i=1;i<=n;i++){
tmp[i]=a[i];
while(tmp[i]>x) tmp[i]/=2;
if (tmp[i]==0) return false;
while(tmp[i]&&vis[tmp[i]]) tmp[i]/=2;
if (tmp[i]==0) return false;
vis[tmp[i]]=true;
}
return true;
}
int main(){
freopen("input.txt","r",stdin);
while(scanf("%d",&n)!=EOF){
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
int L=1,R=2e9,mid;
while(L<=R){
mid=(L+R)>>1;
if (check(mid)){
for(int i=1;i<=n;i++) ans[i]=tmp[i];
R=mid-1;
}
else
L=mid+1;
}
for(int i=1;i<=n;i++)
printf("%d%c",ans[i],i==n?'\n':' ');
}
return 0;
}