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的影响力

未完待续

posted @ 2020-02-06 00:22  君月白吖  阅读(320)  评论(0编辑  收藏  举报