2020牛客寒假算法基础集训营4

A.
已知 gcd(a,b) 共递归了 n次,求所有可能的a,b中满足a>b>=0且a+b最小的一组的a与b之和。

思路:枚举几个就发现是斐波那契数列 打个表就好了 而且这个n <= 80 很耐人寻味 斐波那契数列小于80的时候LL是存的下的

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <algorithm>
#include <set>
#include <map>
#include <vector>
#include <stack>
#include <queue>

using namespace std;
typedef long long LL ;
typedef pair<int,int> pii;

#define fi first
#define se second

const int INF = 0x3f3f3f3f;
const double eps = 1e-7;
const double pi=acos(-1);

const int N = 3005;
const int M = 2005;
const int mod = 1e9+7;

LL f[105];

int main()
{
    int t ;

    f[0] = 1,f[1] = 3,f[2] = 5;
    for(int i = 3; i < 81 ;i ++)
        f[i] = f[i-1]+f[i-2];

    cin >> t;

    while(t --)
    {
        LL n;

        cin >> n;

        cout << f[n] << '\n';
    }
    return 0;
}

B.

题意:括号匹配
思路:用栈模拟就好 左括号全部入栈 如果遇到右括号 就判断当前栈是否为空(这个很重要 空栈弹出会报RE的)栈顶元素是否匹配 最后再检查栈内的元素是否全部匹配完就好了

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <algorithm>
#include <set>
#include <map>
#include <vector>
#include <stack>
#include <queue>

using namespace std;
typedef long long LL ;
typedef pair<int,int> pii;

#define fi first
#define se second

const int INF = 0x3f3f3f3f;
const double eps = 1e-7;
const double pi=acos(-1);

const int N = 3005;
const int M = 2005;
const int mod = 1e9+7;

char s[1000005];
stack <char> st;

int main()
{
    scanf("%s",s);

    bool flag = 0;

    int len = strlen(s);

    if(len == 0)
    {
        cout << "Yes" << '\n';
        return 0;
    }

    if(len == 1)
    {
        cout << "No" << '\n';
        return 0;
    }

    for(int i = 0; i < len; i ++)
    {
        if(s[i] == '(')
            st.push(s[i]);

        if(s[i] == '[')
            st.push(s[i]);

        if(s[i] == '{')
            st.push(s[i]);

        if(s[i] == ')')
        {
            if(!st.empty() && st.top() == '(')
                st.pop();
            else
            {
                flag = 1;
                break;
            }
        }

        if(s[i] == ']')
        {
            if(!st.empty() && st.top() == '[')
                st.pop();
            else
            {
                flag = 1;
                break;
            }
        }

        if(s[i] == '}')
        {
            if(!st.empty() && st.top() == '{')
                st.pop();
            else
            {
                flag = 1;
                break;
            }
        }
    }

    if(!flag && st.empty())
        cout << "Yes" << '\n';
    else
        cout << "No" << '\n';

    return 0;
}

C.
题意:给一个长度为n的序列 求长度为k的连续字段乘积对998244353取模的最大值
思路:两种思路,但本质都是维护一个长度为k的字段 1是用线段树维护 2.是直接维护 但会出现逆元 所以会更麻烦些

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <algorithm>
#include <set>
#include <map>
#include <vector>
#include <stack>
#include <queue>

using namespace std;
typedef long long LL ;
typedef pair<int,int> pii;

#define fi first
#define se second

const int INF = 0x3f3f3f3f;
const double eps = 1e-7;
const double pi=acos(-1);

const int N = 2e5+5;
const int M = 2005;
const int mod = 998244353;

struct node
{
    int l,r;
    LL x;
    LL sum;
}t[N << 2];

void build(int v,int l,int r)
{
    t[v].l = l;
    t[v].r = r;
    if(l == r)
    {
        scanf("%lld",&t[v].x);
        t[v].sum = t[v].x;
        return ;
    }

    int mid = l+r>>1;

    build(v << 1,l,mid);
    build(v << 1|1,mid+1,r);

    t[v].sum = t[v<<1].sum*t[v<<1|1].sum%mod;///父节点的值为左右结点的乘积
}

LL query(int v,int x,int y)
{
    if(t[v].l == x && t[v].r == y)
    {
         return t[v].sum ;
    }


    int mid = t[v].l+t[v].r >> 1;

    if(y <= mid)
        query(v << 1,x,y);
    else
    {
        if(x > mid)
            query(v << 1|1,x,y);
        else
            return query(v << 1,x,mid)*query(v << 1|1,mid+1,y)%mod;
    }
}

int main()
{
    int n,k;

    cin >> n >> k;

    build(1,1,n);

    LL res = 0;

    for(int i = 1;i <= n-k+1;i ++)
    {
        res = max(res,query(1,i,i+k-1));
    }

    printf("%lld\n",res);

    return 0;
}


#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <algorithm>
#include <set>
#include <map>
#include <vector>
#include <stack>
#include <queue>
 
using namespace std;
typedef long long LL ;
typedef pair<int,int> pii;
 
#define fi first
#define se second
 
const int INF = 0x3f3f3f3f;
const double eps = 1e-7;
const double pi=acos(-1);
 
const int N = 2e5+5;
const int M = 2005;
const LL mod = 998244353;
 
LL a[1000010];
 
LL quickpow(LL a,LL b)
{
    LL res = 1;
 
    while(b)
    {
        if(b&1)
            res = res*a%mod;
 
        b >>= 1;
 
        a = a*a%mod;
    }
 
    return res;
}
 
int main()
{
    ios::sync_with_stdio(false);
 
    int n,k;
 
    cin >> n >> k;
 
    LL res = 0;
    LL temp = 1;
    LL cnt = 0;
 
    for(int i = 1;i <= n;i ++)
    {
        cin >> a[i];
 
        if(a[i] == 0)
            temp = 1,cnt = 0;
        else
        {
            cnt ++ ;
 
            temp = temp*a[i]%mod;
 
            if(cnt == k)
            {
                res = max(res,temp);
                temp = temp*quickpow(a[i-k+1],mod-2)%mod;///处理逆元
                cnt -- ;
            }
        }
    }
 
    printf("%lld\n",res);
 
    return 0;
}

D.
题意:给出长度n的序列 求有多少个不同的l,r序列异或和为0
思路:先求出前缀异或和 根据题意 sum[r] ^ sum[l-1] = 0 所以 sum[r] = sum[l-1]
遍历一遍用map标记有多少个数为相同的前缀异或值

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <algorithm>
#include <set>
#include <map>
#include <vector>
#include <stack>
#include <queue>

using namespace std;
typedef long long LL ;
typedef pair<int,int> pii;

#define fi first
#define se second

const int INF = 0x3f3f3f3f;
const double eps = 1e-7;
const double pi=acos(-1);

const int N = 2e5+5;
const int M = 2005;
const LL mod = 998244353;

LL a[200010];
map <LL,int> mp;

int main()
{
    int n;

    cin >> n;

    LL now = 0;
    LL res = 0;

    mp[0] = 1;
    
    for(int i = 0;i < n;i ++)
    {
         int x;

         cin >> x;

         now ^= x;

         res += mp[now];
         mp[now] += 1;
    }

    cout << res << '\n';

    return 0;
}


D.

思路:贪心模拟 尽量 把小的数放在最高位置上 大的数放在低位置上就好

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <algorithm>
#include <set>
#include <map>
#include <vector>
#include <stack>
#include <queue>

using namespace std;
typedef long long LL ;
typedef pair<int,int> pii;

#define fi first
#define se second

const int INF = 0x3f3f3f3f;
const double eps = 1e-7;
const double pi=acos(-1);

const int N = 5e5+5;
const int M = 2005;
const int mod = 1e9+7;

int pos,cnt;
char a[N],s[N];
int b[N];

int main()
{
    scanf("%s",a+1);

    int len = strlen(a+1);

    for(int i = 1;i <= len;i ++)
    {
        if(a[i] != '+')
           s[++cnt] = a[i];
    }

    sort(s+1,s+cnt+1);
    pos = len-cnt+1;

   /// printf("pos %d\n",pos);

    for(int i = cnt,tail = 1;i > 0;i -= pos ,tail ++)
    {
        for(int j = i;j > max(0,i-pos);j --)
        {
          //  printf("i %d %c\n",i,s[j]);
            b[tail] += s[j]-'0';
        }
    }

    for(int i = 1;i <= 500050;i ++)
    {
        if(!b[i])
        {
            pos = i;
            break;
        }

        b[i+1] += b[i]/10;
        b[i] %= 10;
    }

    for(int i = pos-1;i > 0;i --)
    {
        printf("%d",b[i]);
    }
    printf("\n");
    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值