2020牛客寒假算法基础集训营 一
题目链接:https://ac.nowcoder.com/acm/contest/3002
官方题解链接:https://ac.nowcoder.com/discuss/364600
A.honoka和格点三角形
知识点:计数原理
分析:
由题目可以知道三角形只有底1高2和底2高1两种情况,然后有三角形两边平行和只有一边平行两种情况,这个时候分类讨论并且注意不要重复就可以了
代码如下:
#include<bits/stdc++.h>
typedef long long int ll ;
const int mod = 1e9 + 7 ;
using namespace std ;
int main()
{
ll n , m ;
cin >> n >> m ;
ll ans1 = (((n - 2) * (n - 2)) % mod * (2 * m - 2)) % mod ;
ll ans2 = (((m - 2) * (m - 2)) % mod * (2 * n - 2))% mod ;
ll ans3 = (((n - 1) * n)% mod * (2 * m - 4))% mod ;
ll ans4 = (((m - 1) * m) % mod * (2 * n - 4)) % mod ;
cout << (ans1 + ans2 + ans3 + ans4) % mod << endl ;
return 0 ;
}
B.kotori和bangdream
知识点:概率论
分析:
非常简单的期望问题,不多赘述,注意double类型即可,因为 int/int = int
代码如下:
#include<bits/stdc++.h>
typedef long long int ll ;
using namespace std ;
int main()
{
double n , x , a , b ;
cin >> n >> x >> a >> b ;
double ans = n * a * x / 100 + n * b * (100 - x) / 100 ;
printf("%.2lf\n" , ans) ;
return 0 ;
}
C.umi和弓道
D.hanayo和米饭
签到题
分析:非常简单的求数组中缺少的一项,直接暴力循环就可,这里用的等差数列求和做了进一步的优化
代码如下:
#include<bits/stdc++.h>
typedef long long int ll ;
using namespace std ;
int main()
{
ll n , a[100005] = {0} ;
cin >> n ;
ll ans = (n + 1)*n / 2 ;
ll sum = 0 ;
for(int i = 0 ; i < n - 1; ++i)
{
scanf("%lld" , &a[i]) ;
sum += a[i] ;
}
cout << ans - sum << endl ;
return 0 ;
}
E.rin和快速迭代
知识点:简单数论
分析:
就是一个很暴力的披着数论皮的题吧。直接用sqrt求一个数的因子的个数就可以了
sqrt原因:x的因数成对出现(一个数若是可以进行因数分解,那么分解时得到的两个数一定是一个小于等于根号x另外一个大于等于根号x,如24,他的因数有1,2,3,4,6,8,12,24,根据定义,不考虑1和他本身,那么若2,3,4是某个数的因数,那么另外几个数也是这样的。所以对于任意的一个x,我们只需要从1枚举到根号x就可以了.
代码如下:
#include<bits/stdc++.h>
typedef long long int ll ;
using namespace std ;
ll num(ll n)
{
if(n == 1)
return 1 ;
ll count = 2 ;
for(ll i = 2 ; i <= sqrt(n) ; ++ i)
{
if(n % i == 0)
{
if(i == sqrt(n) && n / i == i) //边界
{
count ++ ;
}
else
count += 2 ;
}
}
return count ;
}
int main()
{
ll n ;
scanf("%lld" , &n) ;
ll k = 0 ;
ll t = 0 ;
while(k != 2)
{
k = num(n) ;
n = k ;
t ++ ;
}
printf("%lld\n" , t) ;
return 0 ;
}
F.maki和tree
G.eli和字符串
知识点:字符串
分析:
这道题我采用的尺取法来做的,也就是先将右指针往右边移动,直到某个字符的出现次数达到k次为止,然后再移动左指针,使范围缩小
代码如下:
#include<bits/stdc++.h>
using namespace std ;
int main()
{
int n , k ;
char s[200005] ;
int num[30] ;
cin >> n >> k ;
cin >> s ;
int ans = 0x3f3f3f3f ;
for(int i = 0 , j = 0 ; i < n ; ++ i )
{
//i是右边界,j是左边界
num[s[i] - 'a'] ++ ;
while(num[s[i] - 'a'] == k) // 出现k次
{
if(ans > i - j + 1)
{
ans = i - j + 1 ;
}
num[s[j] - 'a'] -- ;
j ++ ; //左边界往右移动
}
}
if(ans == 0x3f3f3f3f)
printf("-1\n") ;
else
printf("%d\n" , ans) ;
return 0 ;
}
H.nozomi和字符串
知识点:字符串
分析:这里是尺取法配合双端队列食用,先用双端队列,以1和0为本体各扫一遍。以0为本体的时候,扫到1的话就添加到双端队列里面,如果超过k个,就从左端弹出,要求一直保持里面剩k个,同时记录0的子序列的区间左端。在弹出的时候更新start = De.front + 1,并且时刻更新ans
代码如下:
#include<bits/stdc++.h>
using namespace std ;
int main()
{
int n, k, start , ans ;
string s ;
cin >> n >> k ;
cin >> s ;
ans = 0;
start = 0 ;
deque<int> De;
for(int i = 0; i < n; i++)
{
if(s[i] == '0')
De.push_back(i) ;
if(De.size() > k)
{
start = De.front() + 1 ;
De.pop_front() ;
}
ans = max(ans, i - start + 1) ;
}
De.clear() ;
start = 0 ;
for(int i = 0 ; i < n ; ++ i)
{
if(s[i] == '1')
De.push_back(i) ;
if(De.size() > k)
{
start = De.front() + 1 ;
De.pop_front() ;
}
ans = max(ans, i - start + 1) ;
}
cout << ans << endl ;
return 0 ;
}
I.nico和niconiconi
J.u's的影响力
未完待续