NEFU大一省赛训练1(全题解)

OP

一个半小时七道题,两个小时一道题555;
G题鲨我;

A 哪些数不在

差分

思路

即在区间左端点标记+1,右端点标记-1;

遍历所有可行范围,遇到+1即计数值+1,-1亦然;

处理好开闭问题后,计数值为0的位置即没有被线段覆盖;

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

int main()
{
int a[102],n,m,l,r,i;
while(~scanf("%d",&m))
{
memset(a,0,sizeof a);
scanf("%d",&n);
while(m--)
{
scanf("%d%d",&l,&r);
a[l-1]++,a[r]--;
}
queue<int>que;
int c=a[0];
for(i=1;i<=n;i++)
{
if(!c)que.push(i);
c+=a[i];
//printf("*");
}
printf("%d\n",que.size());
while(que.size())
{
printf("%d%c",que.front(),que.size()-1?' ':'\n');
que.pop();
}
}
return 0;
}

B 闹钟

gcd

思路

要求从第一个工作开始时间开始,所有工作开始时间均响铃,即求所有工作开始时间与第一次工作开始时间的差的最大公倍数;

再遍历所有可行响铃间隔,找出第一个满足条件的即可;

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

int main()
{
int n,m,i;
ll del=0,g,mk;
cin>>n>>m;
cin>>mk;
for(i=1;i<=n-1;i++)
{
scanf("%lld",&g);
g-=mk;
if(!del)del=g;
else del=__gcd(del,g);
}
for(i=1;i<=m;i++)
{
scanf("%lld",&g);
if(del%g==0)break;
}
if(i<=m)printf("YES\n%d\n",i);
else printf("NO\n");
return 0;
}

C 减法

思路

对于这个数据量,模拟的话大概会爆TLE,于是我打算记录累计减去的值;

在代码中,这个值即为del;
原题中所求的最小非零值即为最小的大于del的值;

再累加减去的值即可(注意每次减去的值不是找到的数本身,而是找到的数减去该次del值);

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

int main()
{
ll del=0,a[100005]={0};
int n,k,i;
cin>>n>>k;
for(i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
sort(a+1,a+1+n);
//printf("%d\n",&a[3]);
while(k--)
{
ll *p=upper_bound(a+1,a+n+1,del);
// printf("%d %d %lld\n",p,a+n+1,del);
if(p==a+n+1)printf("0\n");
else printf("%lld\n",*p-del),del+=*p-del;
}
return 0;
}

D 隧道

bfs

思路

大致估计了一下,对于目标块每一个点进行n2n^2遍历时间复杂度也遭得住,也没想到比较好的办法进一步降低时间复杂度,于是做得比较暴力;

对于起始点进行正常的bfs形成起始块,如果目标点已达,则输出0;
否则对目标点bfs,再对连通块中的每一个点算出距离起始块对应最近点的距离;

os:竟然在字符串处理上栽了一发;

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int c=1,n;//这道题代码贼乱,有两个bfs函数和一个求距离函数
int mp[51][51]={0},gt[51][51]={0};
void bfs(int xi,int xj)
{
int di[]={0,0,1,-1},dj[]={1,-1,0,0};
gt[xi][xj]=c;
int ct=1;
queue<pair<int ,int> >que;
que.push({xi,xj});
while(!que.empty())
{
pair<int,int>now=que.front();
que.pop();
for(int k=0;k<4;k++)
{
if(now.first+di[k]>=1&&now.first+di[k]<=n
&&now.second+dj[k]>=1&&now.second+dj[k]<=n
&&mp[now.first+di[k]][now.second+dj[k]]
&&!gt[now.first+di[k]][now.second+dj[k]])
que.push({now.first+di[k],now.second+dj[k]})
,gt[now.first+di[k]][now.second+dj[k]]=c,ct++;
}
}
c++;
//printf("%d\n",ct);
}
ll gdis(int xi,int xj)
{
ll md=100005;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
if(gt[i][j]==1)
{
md=min(md,(ll)(xi-i)*(xi-i)+(xj-j)*(xj-j));
}
}
return md;
}
ll bfs1(int xi,int xj)
{
int di[]={0,0,1,-1},dj[]={1,-1,0,0};
gt[xi][xj]=c;
int ct=1;
queue<pair<int ,int> >que;
que.push({xi,xj});
ll mdis=gdis(xi,xj);
while(!que.empty())
{
pair<int,int>now=que.front();
que.pop();
for(int k=0;k<4;k++)
{
if(now.first+di[k]>=1&&now.first+di[k]<=n
&&now.second+dj[k]>=1&&now.second+dj[k]<=n
&&mp[now.first+di[k]][now.second+dj[k]]
&&!gt[now.first+di[k]][now.second+dj[k]])
que.push({now.first+di[k],now.second+dj[k]})
,gt[now.first+di[k]][now.second+dj[k]]=c
,mdis=min(mdis,gdis(now.first+di[k],now.second+dj[k])),ct++;
}
}
c++;
//printf("%d\n",ct);
return mdis;
}
int main()
{
int fi,fj,ti,tj,i,j;
//char g;
cin>>n;
cin>>fi>>fj>>ti>>tj;
string g;
for(i=1;i<=n;i++)
{
cin>>g;
for(j=0;j<n;j++)
{
if(!(g[j]-'0'))mp[i][j+1]=1;
}
}
bfs(fi,fj);
if(gt[ti][tj])
{
printf("0");
}
else
{
ll ans=bfs1(ti,tj);
printf("%lld",ans);
}
return 0;
}

E 尖括号

思路

对于一个尖括号串,最左侧的>右面的所有符号均可以被其消去,操作后此符号在最右端,最右侧的<同理;

接下来为了仅剩一个符号,我们需要统计要使 以上符号出现在在对应的端点 所需要删除的符号数并取最小值;
(即对于<<<<>>><><<>,若使最左侧的>出现在左端,则需要删去左侧的四个<,若使最右侧的<出现在最右端,需要删去右侧的一个>,故最小删去数为1)

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

int main()
{
int t,n,i;
string g;
cin>>t;
while(t--)
{
int n;
cin>>n>>g;
if(n==1)printf("0\n");
else
{
int dl=0,dr=0;
for(i=0;g[i];i++)
{
if(g[i]=='<')dl++;
else break;
}
for(i=n-1;i>=0;i--)
{
if(g[i]=='>')dr++;
else break;
}
printf("%d\n",min(dl,dr));
}
}
return 0;
}

F 恐龙的故事

素数筛,模拟

思路

模拟即可

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int p[10000007] , num[10000007] , pp[10000007];
int main()
{
int c=0,cc=0;
num[0]=1,num[1]=1;
for(int i=2;i<=10000000;i++)
{
if(!num[i])p[c++]=i;
for(int j=0;j<c&&i*p[j]<10000000;j++)
{
num[i*p[j]]=1;
if(i%p[j]==0)break;
}
}
for(int i=0;i<c;i++)
{
if(!num[i+1])pp[cc++]=p[i];
}
//for(int i=0;i<cc;i++)printf("%d\n",pp[i]);
int t,m;
cin>>t;
while(t--)
{
cin>>m;
int *p=lower_bound(pp,pp+cc,m);
printf("%d\n",*p);
}
return 0;
}

G 序列和

思路

这个题的描述有一些些些些问题,实际上需要输出的的是以x+y为第一排序依据升序排序,以x为第二排序依据降序排序之后的第一个;

为方便描述我们将删除序列中一个元素后的序列和称为缺刻和;
对于所有的缺刻和,我们只需要记录能满足该缺刻和的所有序列中,序列号最小的两个序列号;

在对所有缺刻和寻找符合要求的x+y即可;

注:这道题个人既被卡过空间,又被卡过时间,经测试,unordered_map所用空间比map少1/10左右;
用时:1077ms/2000ms,空间占用:60236k/65535k

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

unordered_map<int,pair<int,int> >mp;
unordered_map<int,pair<int,int> >::iterator it1;

int main()
{
int g[200005]={0};
int k,n;
cin>>k;

for(int i=1;i<=k;i++)
{
scanf("%d",&n);
int sum=0;
for(int j=1;j<=n;j++)
{
scanf("%d",&g[j]);
sum+=g[j];
}
for(int j=1;j<=n;j++)
{
if(!mp[sum-g[j]].first)mp[sum-g[j]].first=i;
else if(!mp[sum-g[j]].second&&mp[sum-g[j]].first!=i)mp[sum-g[j]].second=i;//避免我重我自己
}
}
int f=0,mx=k+1,my=k+1;
for(it1=mp.begin();it1!=mp.end();it1++)
{
if(it1->second.first&&it1->second.second)//两个均有值才参与排序
{
int a=it1->second.first;
int b=it1->second.second;
if(a+b<mx+my||(a+b==mx+my&&b<my))//注意第二排序依据
{
mx=min(a,b),my=max(a,b);
}
}
}
if(mx!=k+1)printf("YES\n%d %d",mx,my);//mk被更新过
else printf("NO");
//printf("\n%d",mp.size());
return 0;
}

H 巧克力

模拟

思路

按要求模拟即可

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

int main()
{
int t;
cin>>t;
while(t--)
{
int s,a,b,c;
cin>>s>>a>>b>>c;
ll ans=0;
ans=s/c;
ans+=b*(ans/a);
printf("%lld\n",ans);
}
return 0;
}

ED

\


NEFU大一省赛训练1(全题解)
https://tanyuu.github.io/2021.01-06/NEFU大一省赛训练1(全题解)/
作者
F Juny
发布于
2021年5月3日
许可协议