2018东北农业大学春季校赛

2018东北农业大学春季校赛

B

题目要求

给你一个nn矩阵,按照顺序填入1到nn的数,例如n=5,该矩阵如下

现在让你连接相邻两条边的中点,然后只保留他们围成封闭图形区域的数字,那么这个矩阵变为

现在你们涵哥让你求变化后的矩阵的所有元素的和为多少

输入描述
输入第一行一个整数T(1<=T<=100)
接下来有T组测试数据,每组测试数据输入一个整数n(3<=n<=10000)
保证输入的n为奇数

输出描述
对于每组测试数据,输出对应答案

输入
2
3
5

输出
25
169

参考AC代码

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
#include<bits/stdc++.h>
#define LL long long
using namespace std;
int t,n;
int main(){
// freopen("input.txt","r",stdin);
cin>>t;
while(t--){
cin>>n;
int st=(n+1)/2,ed=0;
LL ans=0;
ans+=(LL)st;
for(int i=2;i<=n/2+1;i++){
st=st+(n-(2*i-3))+(2*i-4);
ed=st+(2*i-2);
ans+=(LL)(st+ed)*(2*i-1)/2;
// cout<<st<<" "<<ed<<endl;
}
st=n*n-n/2;
ans+=(LL)st;
for(int i=2;i<=n/2;i++){
st=st-(n-(2*i-3))-(2*i-4);
ed=st-(2*i-2);
ans+=(LL)(st+ed)*(2*i-1)/2;
// cout<<st<<" "<<ed<<endl;
}
cout<<ans<<endl;
}
return 0;
}

思路

手动算出每行的st和ed 然后用等差数列求和公式 累加即可
注意n/2到n的公式与1到n/2+1的公式相似 但下半部分要从n到n/2逆推才参考上半部分的公式

D

题目要求
给你一个n×m的迷宫,这个迷宫中有以下几个标识:
s代表起点
t代表终点
x代表障碍物
.代表空地
现在你们涵哥想知道能不能从起点走到终点不碰到障碍物(只能上下左右进行移动,并且不能移动到已经移动过的点)。

输入描述
输入第一行一个整数T(1<=T<=10)
接下来有T组测试数据,对于每一组测试数据,第一行输入2个数n和m(1<=n,m<=500)
接下来n行,每行m个字符代表这个迷宫,每个字符都是上面4个中的一种
数据保证只有一个起点和一个终点

输出描述
对于每一组测试数据,如果可以的话输出YES,不可以的话输出NO

输入
1
3 5
s…x
x…x
…tx

输出
YES

参考AC代码

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
#include<bits/stdc++.h>
#define maxn 550
using namespace std;
int t,n,m;
int sx,sy,ex,ey;
int flag;
char mp[maxn][maxn];
int vis[maxn][maxn];
int dirx[4]={0,0,1,-1};
int diry[4]={1,-1,0,0};
bool check(int x,int y){
if(x<1 || x>n || y<1 || y>m || vis[x][y] || mp[x][y]=='x') return true;
return false;
}
void dfs(int x,int y){
if(x==ex && y==ey){
flag=1;
return;
}
for(int i=0;i<4;i++){
int nextx=x+dirx[i];
int nexty=y+diry[i];
if(check(nextx,nexty)) continue;
vis[nextx][nexty]=1;
dfs(nextx,nexty);
}
}
int main(){
// freopen("input.txt","r",stdin);
cin>>t;
while(t--){
cin>>n>>m;
for(int i=1;i<=n;i++){
scanf("%s",mp[i]+1);
}
flag=0;
memset(vis,0,sizeof vis);
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(mp[i][j]=='s') sx=i,sy=j;
if(mp[i][j]=='t') ex=i,ey=j;
}
}
vis[sx][sy]=1;
dfs(sx,sy);
if(flag) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
return 0;
}

思路

dfs裸搜 注意不需要回溯

E

题目要求
求n的阶乘末尾0的个数

输入描述
输入第一行一个整数T(1<=T<=100),代表测试组数
接下来T行,每行一个数n(1<=n<=10^9)

输出描述
对于每组测试数据,输出对应答案

输入
5
1
2
3
4
5

输出
0
0
0
0
1

参考AC代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include<bits/stdc++.h>
using namespace std;
int t,n;
int main(){
// freopen("input.txt","r",stdin);
cin>>t;
while(t--){
cin>>n;
int num=0,tmp=5;
while(1){
if(n/tmp==0) break;
num+=n/tmp;
tmp*=5;
}
cout<<num<<endl;
}
return 0;
}

思路

转跳链接

F

题目要求
你们wyh学长给你n个点,让你分成2个集合,然后让你将这n个点进行两两连接在一起,连接规则是这样的

  1. 连接的两个点必须在不同的两个集合
  2. 一个集合内部任意两个点之间不能相连
    现在,wyh学长需要让你将这n个点任意分成2个集合之后,最多能连接多少条边?

输入描述
输入第一行一个整数T(1<=T<=100000)
接下来T组测试数据,每组测试数据输入一个整数n(1<=n<=100000)

输出描述
对于每组测试数据,输出对应答案

输入
4
0
1
2
4

输出
0
0
1
4

参考AC代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include<bits/stdc++.h>
#define LL long long
using namespace std;
int t,n;
int main(){
// freopen("input.txt","r",stdin);
cin>>t;
while(t--){
cin>>n;
if(n&1) cout<<(LL)(n/2)*(n/2+1)<<endl;
else cout<<(LL)(n/2)*(n/2)<<endl;
}
return 0;
}

思路

分成两部分集合 均分成就是:(偶数)偶数×偶数 (奇数)奇数×偶数

I

题目要求
wyh学长现在手里有n个物品,这n个物品的重量和价值都告诉你,然后现在让你从中选取k个,问你在所有可能选取的方案中,最大的单位价值为多少(单位价值为选取的k个物品的总价值和总重量的比值)

输入描述
输入第一行一个整数T(1<=T<=10)
接下来有T组测试数据,对于每组测试数据,第一行输入两个数n和k(1<=k<=n<=100000)
接下来有n行,每行两个是a和b,代表这个物品的重量和价值

输出描述
对于每组测试数据,输出对应答案,结果保留两位小数

输入
1
3 2
2 2
5 3
2 1

输出
0.75

参考AC代码

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
#include<bits/stdc++.h>
#define maxn 100050
using namespace std;
const double eps = 1e-4;
int t,n,k;
double a[maxn];
double value[maxn],weight[maxn];
bool cmp(double a,double b){
return a>b;
}
bool check(double x){
memset(a,0,sizeof a);
for(int i=1;i<=n;i++) a[i]=value[i]-x*weight[i];
sort(a+1,a+1+n,cmp);
double ans=0;
for(int i=1;i<=k;i++) ans+=a[i];
return ans>=0;
}
int main(){
// freopen("input.txt","r",stdin);
cin>>t;
while(t--){
cin>>n>>k;
for(int i=1;i<=n;i++) cin>>weight[i]>>value[i];
double l=0.0,r=100000000.0,ans=0.0;
while(l-r<=eps){
double mid=(l+r)/2.0;
if(check(mid)){
ans=mid;
l=mid+eps;
}
else r=mid-eps;
}
printf("%.2lf\n",ans);
}
return 0;
}

思路

分数最优规划 二分
列出右移的不等式:value(k个)/weight(k个)>=mid 化简:value(k个)-mid×weight(k个)>=0 由于每个物品的value和weight是相互独立的 所以可以排序取前k大
check函数为:修改后的函数为:value[i]-mid×weight[i] 设为数组a
取a的前k大元素判断是否大于等于0 若满足l右移 否则r左移
注意double二分精度要比题目要求大1e-2

K

题目要求
wyh学长特别喜欢斐波那契数列,F(0)=0,F(1)=1,F(n)=F(n-1)+F(n-2)(n>=2)
一天他突发奇想,想求F(a^b)%c

输入描述
输入第一行一个整数T(1<=T<=100),代表测试组数
接下来T行,每行三个数 a,b,c (a,b<=2^64) (1<c<1000)

输出描述
输出第a^b项斐波那契数对c取余的结果

输入
3
1 1 2
2 3 1000
32122142412412142 124124124412124 123

输出
1
21
3

参考AC代码

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
#include<bits/stdc++.h>
#define LL unsigned long long
#define maxn 1000050
using namespace std;
int t,c;
int f[maxn];
LL a,b;
LL qpow(LL x,LL y,int mod){
LL re=1,base=x%mod;
while(y){
if(y&1) re=(re*base)%mod;
base=(base*base)%mod;
y>>=1;
}
return re;
}
int main(){
// freopen("input.txt","r",stdin);
cin>>t;
while(t--){
cin>>a>>b>>c;
f[0]=0,f[1]=1;
int num=0;
for(int i=2;i<=1000100;i++){
f[i]=(f[i-1]+f[i-2])%c;
if(f[i-1]==0 && f[i]==1){
num=i-1;
break;
}
}
int pos=qpow(a,b,num);
cout<<f[pos]<<endl;
}
return 0;
}

思路

找出循环节+快速幂
因为题目有mod c 所以肯定存在循环节 for循环找出循环节
因为循环节小于等于1000×1000 存在100w的斐波拉契数列直接预处理 不需要矩阵快速幂
答案就是f[a^b%循环节] 数组位置pos二分快速幂

L

题目要求
你们wyh学长小时候住在河边,因为周围的生态环境非常好,所以经常会有天鹅浮在湖面上,每只天鹅都长得不一样,它们偶尔排成一排,偶尔分散开,偶尔也会去其他河畔,wyh学长为了统计它们的个数,编了一个程序赋予它们一个“萌”值,但是这些天鹅很不听话,一会儿会从别的地方游过来一两只,一会儿又会在统计过程中游走一两只,现在请你帮他完成统计任务。

输入描述
共有T(T<=10)组数据,每组数据第一行为两个数 N, M (N,M <= 500000),代表有N只天鹅和M次操作,接下来一行是N个数字,下面M行首先会输入一个字符串S,接着会有三类操作,如果S是“insert”,接着输入一个正整数a,代表插入一只“萌”值为a的天鹅,如果S是“delete”,接着输入一个正整数a,代表删除一只“萌”值为a的天鹅,如果S是“query”,接着输入一个正整数k,代表查询“萌”值第k大的天鹅。
萌值为[1,1000000000],并且保证一定存在第k大

输出描述
对应每次询问,输出询问结果。

输入
1
5 4
6 4 2 9 1
query 2
insert 7
delete 6
query 2

输出
6
7

参考AC代码

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
97
#include<bits/stdc++.h>
#define Lc (o -> Ch[0])
#define Rc (o -> Ch[1])
#define val (o -> v)
#define pre (o -> p)
#define siz (o -> S)
using namespace std;
const int Maxn = 500050;
struct Treap{
Treap* Ch[2];
int p,v,S;
};
int root = 0,n,q,x,a[Maxn];
void Update(Treap* &o){
siz = 1;
if(Lc != NULL)siz += Lc -> S;
if(Rc != NULL)siz += Rc -> S;
}
void Rotate(Treap* &o,int d){
Treap* P = o -> Ch[d^1];
o -> Ch[d^1] = P -> Ch[d];
P -> Ch[d] = o;
Update(o);Update(P);
o = P;
}
void Insert(Treap* &o,int x){
o = new Treap();
Lc = Rc = NULL;
pre = rand();val = x;
}
else {
int d = x < val;
Insert(o -> Ch[d],x);
if( ( pre ) > o -> Ch[d] -> p)Rotate(o,d^1);
}
Update(o);
}
int Find(Treap* o,int x){
while(o != NULL){
if(val == x)return 1;
o = (x < val) ? Rc : Lc ;
}return 0;
}
void Delete(Treap* &o,int x){
if(val == x){
if(Lc == NULL)o = Rc;
else if(Rc == NULL)o = Lc;
else {
int T = (Lc -> p) < (Rc -> p);
Rotate(o,T);Delete(o -> Ch[T],x);
}
}
else Delete(o -> Ch[x < val],x);
if(o != NULL)Update(o);
}
int Kth_Min(Treap* o,int k){
if(o == NULL || k <= 0 || k > siz)return 0;
int S = (Rc == NULL) ? 0 : (Rc -> S);
if(k == S + 1)return val;
else if(k <= S)return Kth_Min(Rc,k);
else return Kth_Min(Lc,k - S - 1);
}
int Kth_Max(Treap* o,int k){
if(o == NULL || k <= 0 || k > siz)return 0;
int S = (Lc == NULL) ? 0 : (Lc -> S);
if(k == S + 1)return val;
else if(k <= S)return Kth_Max(Lc,k);
else return Kth_Max(Rc,k - S - 1);
}
void Print(Treap* o){
printf("%d ",siz);
if(Lc != NULL)Print(Lc);
if(Rc != NULL)Print(Rc);
}
char op[100];
int main(){
int t;
cin>>t;
while(t--){
scanf("%d%d",&n,&q);
Treap* Root = NULL;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
Insert(Root,a[i]);
}
while(q--){
scanf("%s",op);
int tmp;
cin>>tmp;
if(op[0]=='i') Insert(Root,tmp);
else if(op[0]=='d') Delete(Root,tmp);
else if(op[0]=='q') printf("%d\n",Kth_Max(Root,tmp));
}
}
return 0;
}

思路

动态区间第k大 带删除插入查询
treap模版即可

M

题目要去
求每一个数字中有多少个数字‘7’

输入描述
输入第一行一个整数T(1<=T<=10)
接下来有T组测试数据,对于每组测试数据,输入一个整数n(1<=n<=10000000000)

输出描述
对于每组测试数据,输出对应答案

输入
2
1234567
123456

输出
1
0

参考AC代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include<bits/stdc++.h>
using namespace std;
int t;
char s[50];
int main(){
// freopen("input.txt","r",stdin);
cin>>t;
while(t--){
scanf("%s",s+1);
int len=strlen(s+1);
int ans=0;
for(int i=1;i<=len;i++){
if(s[i]=='7') ans++;
}
cout<<ans<<endl;
}
return 0;
}

思路

字符串模拟

文章目录
  1. 1. 2018东北农业大学春季校赛
    1. 1.1. B
      1. 1.1.1. 参考AC代码
      2. 1.1.2. 思路
    2. 1.2. D
      1. 1.2.1. 参考AC代码
      2. 1.2.2. 思路
    3. 1.3. E
      1. 1.3.1. 参考AC代码
      2. 1.3.2. 思路
    4. 1.4. F
      1. 1.4.1. 参考AC代码
      2. 1.4.2. 思路
    5. 1.5. I
      1. 1.5.1. 参考AC代码
      2. 1.5.2. 思路
    6. 1.6. K
      1. 1.6.1. 参考AC代码
      2. 1.6.2. 思路
    7. 1.7. L
      1. 1.7.1. 参考AC代码
      2. 1.7.2. 思路
    8. 1.8. M
      1. 1.8.1. 参考AC代码
      2. 1.8.2. 思路
|