京龙杯周赛Round1题解
比赛链接:http://10.11.50.84:8080/contest/24
A题
题目大意
给出一个n,求1到n所有数的和。
难度:easy签到题
解题思路
这个题没有卡O(n),所以暴力遍历也能水过。正解直接套等差数列求和公式n*(n+1)/2即可水过。本题注意开long long
#include<bits/stdc++.h>
using namespace std;
int main()
{
long long int n;
cin>>n;
cout<<n*(n+1)/2;
return 0;
}
B题
题目大意
题意在题目中介绍的很清晰,注意k=0时也可以前进一格
难度:easy
解题思路
由于数据范围很小,贪心、dp、搜索都可以解决,但是贪心、dp做法时间更快。贪心做法就是每次找最大前进步数,如果有障碍就最大步数–,若一直无法前进,就直接break,输出0。
#include<iostream>
#include<cstdio>
using namespace std;
int n,d;
int main()
{
cin>>n>>d;
string s;
cin>>s;
int len = s.length();
int now = 0;
int pre = 0;
bool f = 1;
int t = 0;
while(now != n-1){
now+=d+1;
while(now >= len || s[now] == 'X') now--;
if(now == pre) {
f = 0;
break;
}
t++;
pre = now;
}
if(!f){
cout<<0;
}else{
cout<<t;
}
return 0;
}
然后这个题,我们可以线性DP解决,dp[i]代表到此位置的最小跳跃步数,我们可以得出状态转移方程dp[i]=dp[j]+1,j代表能到达i点的编号,对于j,我们直接枚举遍历即可。
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxN = 111111;
int a[100];
int main(){
string s;
int n,d;
cin>>n>>d;
cin>>s;
for(int i=1;i<n;i++)a[i] = maxN;
for(int i=1;i<n;i++){
for(int j=i-d-1;j<i;j++){
if(j>=0&&s[i]=='.'&&s[j]=='.'){
a[i] = min(a[i],a[j]+1);
}
}
}
// for(int i=0;i<n;i++)cout<<a[i]<<" ";
if(a[n-1]==maxN)cout<<0;
else cout<<a[n-1];
return 0;
}
C题
题目大意
给你一个序列,序列每个数都小于等于长度n,问这个序列是不是长度为n的一个全排列
难度:easy
解题思路
由于全排列的性质,每个数字最多出现一次,所以若有一个数字出现超过1次,那么这个序列肯定不是全排列的一个排列,所以我们开一个数组标记判断即可
#include<iostream>
#include<cstdio>
using namespace std;
bool ton[10085];
int main()
{
int n;
cin>>n;
bool f = 1;
for(int i = 1;i<=n;i++){
int x;
cin>>x;
if(ton[x] == 1){
f = 0;
}else{
ton[x] = 1;
}
}
if(f){
cout<<"Yes";
}else{
cout<<"No";
}
return 0;
}
D题
题目大意
主要就是题面意思,根据题目给出代码,写出自己的优化代码算法
难度:Medium+easy
解题思路
看到大的数据范围,我们就要想到打表找规律或者是数学公式推导,这个题我们需要打表找规律,不难发现每当maxgcd变化时,其对应的值为斐波那契数列的一项,所以根据斐波那契递推公式f[n]=f[n-1]+f[n-2],求解即可
#include<iostream>
using namespace std;
typedef long long ll;
ll x = 1,y = 1,z,n;
int main(){
x = 1;y = 1;
int cnt = 2;
cin>>n;
while(x<=n){
z = x;
x = y + x;
y = z;
cnt++;
}
cout<<cnt-1;
return 0;
}
打表数据:
1 2
2 3
3 4
4 4
5 5
6 5
7 5
8 6
9 6
10 6
11 6
12 6
13 7
14 7
15 7
16 7
17 7
18 7
19 7
20 7
21 8
22 8
23 8
24 8
25 8
26 8
27 8
28 8
29 8
30 8
31 8
32 8
33 8
34 9
35 9
36 9
37 9
38 9
39 9
1 2 3 5 8 13 21 34
E题
题目大意
还是题面本身意思,求数组的一段区间和。
难度:Medium+easy
解题思路
这个题首先我们需要对前缀和有所了解,如果我们对每次询问都用循环求解,显而易见O(n2)会超时,所以我们需要更高级的处理方法降低时间复杂度。这时候我们需要引入前缀和,即预先对数列的1~i处理出前缀和,我们定义sum[i]为数组a[1]…a[i]的和,这样处理之后,我们就可以在每次询问过程中做到O(1)处理答案了,对于l到r的区间和即为sum[r]-sum[l]+a[l]的值,注意本题数据量较大,若用cin和cout会超时,所以选用scanf,printf输入输出
#include<iostream>
#include<cstdio>
using namespace std;
const int maxn=1e6+6;
long long int sum[maxn];
long long int a[maxn];
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
sum[i]=sum[i-1]+a[i];
}
int q;
scanf("%d",&q);
for(int i=1;i<=q;i++)
{
int l,r;
scanf("%d%d",&l,&r);
printf("%lld\n",sum[r]-sum[l]+a[l]);
}
return 0;
}
F题
题目大意
见题面,题面介绍的很清楚了
解题思路
直接根据题意模拟即可,如果是偶数,那么拆分之后两部分也一定是偶数所以就是yes。如果是奇数,肯定分不出两个偶数,所以即为no。注意我们要加一个特判,在偶数情况下,如果是2的情况也是no,因为2只能分为1和1,两个都为奇数,不符合yes的题意。
代码:
#include<iostream>
using namespace std;
typedef long long ll;
int main(){
int a;
cin>>a;
if(a%2)cout<<"No";
else if(a<4)cout<<"No";
else cout<<"Yes";
return 0;
}
比赛过程总结
1.printf与scanf的规范写法
longlong要用%lld
int用%d
2.数组大小
开数组的大小要比规定大小大一些
3.开longlong
看到大于1e9的数据一定要开long long
4.边界数据
在一些小的数据或者是边界情况要加入特判
活动总结
这次题目我们基本面向的是社团新生和刚入门的同学,所以题目难度都较低。每个题都有一定启发性,无论是细节处理还是新算法的引入,都可以让刚入门的同学学到许多新知识。
附难度顺序:
A F C
B
E D