ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

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

2022-02-09 14:06:25  阅读:356  来源: 互联网

标签:leq int ll long 牛客 2022 ans 集训营 mod


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

A-R

长度为\(n\)的字符串,只包含大写字母,问有多少段连续子串能满足包含至少\(k\)个“\(R\)”且不包含“\(P\)”。\((1\leq n\leq200000,1\leq k\leq20)\)

思路

由于不要“\(P\)”,所以就很容易想到在每一段没有“\(P\)”的串中尺取,然后就结束了。

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
char s[1000005];
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    scanf("%s",s+1);
    int pre=1;
    ll ans=0;
    for(int i=1;i<=n+1;i++)
    {
        if(i==n+1||s[i]=='P')
        {
            int l=pre,r=pre;
            int num=(s[l]=='R');
            while(r<i)
            {
                if(num<m)
                {
                    r++;
                    num+=(s[r]=='R');
                }
                if(num>=m)
                {
                    ans+=(i-r);
                    num-=(s[l]=='R');
                    l++;
                }
            }
            pre=i+1;
        }
    }
    printf("%lld\n",ans);
    return 0;
}

B-进制

长度为\(n\)的字符串,\(q\)组操作,每次输入\(3\)个整数\(op,x,y\)。若\(op\)为\(1\),则将第\(x\)个数字改为\(y\);若\(op\)为\(2\),查询区间\([x,y]\)所能表示某进制的最小值(进制必须合法且在二进制到十进制之间,可包含前导0),对\(1e9+7\)取模。\((1\leq n,q\leq10^5)\)

思路

敲十棵线段树应该就能解决问题了吧(逃

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
char s[100005];
ll k[100005];
ll tree[11][400005];
ll poww(ll x,ll n)
{
    ll ans=1;
    while(n)
    {
        if(n&1)(ans*=x)%=mod;
        (x*=x)%=mod;
        n>>=1;
    }
    return ans;
}
void pushup(int p,int l,int r)
{
    int mid=(l+r)>>1;
    tree[1][p]=max(tree[1][p<<1],tree[1][p<<1|1]);
    for(int i=2;i<=10;i++)
    {
        tree[i][p]=(tree[i][p<<1]*poww(i,r-mid)%mod+tree[i][p<<1|1])%mod;
    }
}
void build(int p,int l,int r)
{
    if(l==r)
    {
        for(int i=1;i<=10;i++)tree[i][p]=k[l];
        return;
    }
    int mid=(l+r)>>1;
    build(p<<1,l,mid);
    build(p<<1|1,mid+1,r);
    pushup(p,l,r);
}
void update(int p,int l,int r,int x,int y)
{
    if(l==r)
    {
        for(int i=1;i<=10;i++)tree[i][p]=y;
        return;
    }
    int mid=(l+r)>>1;
    if(x<=mid)update(p<<1,l,mid,x,y);
    else update(p<<1|1,mid+1,r,x,y);
    pushup(p,l,r);
}
ll query(int p,int l,int r,int x,int y,int op)
{
    if(x<=l&&r<=y)
    {
        if(op==1)return tree[op][p];
        else return tree[op][p]*poww(op,y-r)%mod;
    }
    int mid=(l+r)>>1;
    if(op==1)
    {
        ll ans=0;
        if(x<=mid)ans=max(ans,query(p<<1,l,mid,x,y,op));
        if(mid<y)ans=max(ans,query(p<<1|1,mid+1,r,x,y,op));
        return ans;
    }
    else
    {
        ll ans=0;
        if(x<=mid)(ans+=query(p<<1,l,mid,x,y,op))%=mod;
        if(mid<y)(ans+=query(p<<1|1,mid+1,r,x,y,op))%=mod;
        return ans;
    }
}
int main()
{
    int n,q;
    scanf("%d%d",&n,&q);
    scanf("%s",s+1);
    for(int i=1;i<=n;i++)k[i]=s[i]-'0';
    build(1,1,n);
    while(q--)
    {
        int op,x,y;
        scanf("%d%d%d",&op,&x,&y);
        if(op==1)
        {
            update(1,1,n,x,y);
        }
        else
        {
            ll maxx=query(1,1,n,x,y,1);
            printf("%lld\n",query(1,1,n,x,y,maxx+1));
        }
    }
    return 0;
}

C-蓝彗星

有\(n\)颗星,每颗星在天中保留\(t\)秒,\(s_i\)代表第\(i\)颗星的颜色,“\(B\)”代表蓝色,“\(R\)”代表红色,\(a_i\)代表的\(i\)颗星出现的时间,假设黑夜无限长,问能看到蓝色彗星且看不到红色彗星的时长。\((1\leq n,t,a_i\leq100000)\)

思路

对于这样的题目应该一下就能想到差分,一想到差分应该就直接结束了吧……

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll mp[1000005];
char s[1000005];
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    scanf("%s",s+1);
    for(int i=1;i<=n;i++)
    {
        int a;
        scanf("%d",&a);
        if(s[i]=='B')
        {
            mp[a]++;
            mp[a+m]--;
        }
        else
        {
            mp[a]-=1000000;
            mp[a+m]+=1000000;
        }
    }
    ll num=0;
    int tot=0;
    for(int i=0;i<=1000000;i++)
    {
        num+=mp[i];
        if(num>0)tot++;
    }
    printf("%d\n",tot);
    return 0;
}

D-雪色光晕

小红初始位置为\((x_0,y_0)\),她每秒有一个方向向量\((x_i,y_i)\),会沿着该方向跑一秒,小红想知道他在跑步过程中距离小果\((x,y)\)的最近距离。\((1\leq n\leq200000,-10^9\leq x,y,x_i,y_i\leq10^9)\)

思路

这个问题就是判断线段外一点到线段的最短距离是等于到直线的距离还是到端点的距离,然后稍微运用一下高中知识就能轻松\(AC\)了。

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

int main()
{
    int _;
    scanf("%d",&_);
    double x0,y0,x,y;
    scanf("%lf%lf%lf%lf",&x0,&y0,&x,&y);
    double minn=1e9;
    while(_--)
    {
        double x1,y1;
        scanf("%lf%lf",&x1,&y1);
        double ans=fabs(y1*x-x1*y+x1*y0-y1*x0)/sqrt(x1*x1+y1*y1);
        if(x1*(x-x0)+y1*(y-y0)>=0&&(x1*x1+y1*y1)>=((x-x0)*(x-x0)+(y-y0)*(y-y0)-ans*ans))minn=min(minn,ans);
        else minn=min(minn,min(sqrt((x-x0)*(x-x0)+(y-y0)*(y-y0)),sqrt((x-x0-x1)*(x-x0-x1)+(y-y0-y1)*(y-y0-y1))));
        x0+=x1,y0+=y1;
    }
    printf("%.8f\n",minn);
    return 0;
}

E-真假签到题

小红拿到了一份代码:

long long f(long long x)
{
   if(x==1)return 1;
   return f(x/2)+f(x/2+x%2);
}

对于给定的\(x\),问\(f(x)\)是多少。\((1\leq x\leq10^{18})\)

代码

第一道签到题,但是一开始有点慌,规律先错了,哭死。所以其实就是一道输入输出题。

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

int main()
{
    ll n;
    scanf("%lld",&n);
    printf("%lld\n",n);
    return 0;
}

F-小红的记谱法


\((字符串长度不超过1000)\)

思路

这题应该就是一道很简单的模拟题吧……

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
char s[1000005];
int main()
{
    scanf("%s",s+1);
    int num=0;
    int len=strlen(s+1);
    for(int i=1;i<=len;i++)
    {
        if(s[i]=='>')num++;
        else if(s[i]=='<')num--;
        else
        {
            int n=s[i]-'A'+1;
            if((n+7-2)%7==0)printf("7");
            else printf("%d",(n+7-2)%7);
            for(int i=1;i<=num;i++)printf("*");
            for(int i=num;i<=-1;i++)printf(".");
        }
    }
    return 0;
}

G-子序列权值乘积

规定一个数组的权值为最大值乘上最小值。小红有一个数组,问这个数组的所有非空子序列的权值之积对\(1e9+7\)取模后的答案是多少。\((1\leq n\leq200000,1\leq a_i\leq10^9)\)

思路

首先应该就能想到对这个序列排个序,然后对于一个数,他前面有\(a\)个数,后面有\(b\)个数,那么他就有\(2\)的\(a\)次方的机会可以成为最大值,最小值也同理,然后差不多就能结束了,不过还要知道一个芝士点叫做欧拉降幂:

ll phi(ll n)
{
  ll rec=n;
  for(int i=2;i*i<=n;i++)
  {
      if(n%i==0)
      {
          rec=rec-rec/i;
          while(n%i==0) n/=i;
      }
  }
  if(n>1)  rec=rec-rec/n;
  return rec;
}
//一般情况下poww(a,b)%c当b很大时,就能写成
//poww(a,b%phi(mod)+phi(mod))%mod
//而对于gcd(a,mod)==1的情况,phi(mod)就变成了mod-1
//于是得到poww(a,b)%mod==poww(a,b%(mod-1))%mod
//注:对于非特殊情况,"+phi(mod)"不能省

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
ll a[1000005];
ll base[1000005];
ll poww(ll x,ll n)
{
    ll ans=1;
    while(n)
    {
        if(n&1)(ans*=x)%=mod;
        (x*=x)%=mod;
        n>>=1;
    }
    return ans;
}
int main()
{
    int n;
    scanf("%d",&n);
    base[0]=1;
    for(int i=1;i<=n;i++)base[i]=base[i-1]*2%(mod-1);
    for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
    sort(a+1,a+n+1);
    ll ans=1;
    for(int i=1;i<=n;i++)
    {
        (ans*=poww(a[i],base[i-1]+base[n-i]))%=mod;
    }
    printf("%lld\n",ans);
}

H-真真真真真签到题

小红和小紫在一个正方体中,小紫在正中间,小红在角落,两人相距\(x\),问正方体的体积。\((1\leq x\leq100)\)

思路

第二道签到题,没什么难度吧应该……

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

int main()
{
    double dis;
    scanf("%lf",&dis);
    double a=2*sqrt(dis*dis/3);
    printf("%.6f\n",a*a*a);
    return 0;
}

I-爆炸的符卡洋洋洒洒

有\(n\)张符卡,每张符卡的魔力消耗为\(a_i\),威力为\(b_i\)。小红要保证发出的符卡的魔力消耗之和为\(k\)的倍数,问能够发出的最大威力是多少。\((1\leq n,k\leq1000,1\leq a_i,b_i\leq10^9)\)

思路

首先想到的当然是背包,但是\(1e9\)当然是存不下的,但是由于\(k\)的值不大,所以直接存模\(k\)后的值就能轻松解决啦。

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll dp[1005][1005];
int main()
{
    int n,k;
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++)
    {
        ll a,b;
        scanf("%lld%lld",&a,&b);
        for(int j=0;j<k;j++)
        {
            dp[i][a%k]=max(dp[i][a%k],b);
            if(dp[i-1][j])
            {
                dp[i][j]=max(dp[i-1][j],dp[i][j]);
                dp[i][(j+a)%k]=max(dp[i-1][j]+b,dp[i][(j+a)%k]);
            }
        }
    }
    if(dp[n][0]==0)printf("-1\n");
    else printf("%lld\n",dp[n][0]);
}

J-区间合数的最小公倍数

小红有两个整数\(l,r\),问\([l,r]\)中所有合数的最小公倍数是多少,答案对\(1e9+7\)取模。\((1\leq l\leq r\leq30000)\)

思路

这道题我一开始理a假了,其实就是小学的时候求最小公倍数的方法……

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1000000007;
bool prime[30005];
ll t[30005];
ll poww(ll a,ll n)
{
    ll ans=1;
    while(n)
    {
        if(n&1)ans=ans*a%mod;
        a=a*a%mod;
        n>>=1;
    }
    return ans;
}
int main()
{
    for(ll i=2;i<=30000;i++)
        for(ll j=2;j*i<=30000;j++)
            prime[i*j]=1;
    ll l,r;
    scanf("%lld%lld",&l,&r);
    ll num=0;
    for(ll i=l;i<=r;i++)
    {
        if(prime[i])
        {
            num++;
            ll n=i;
            for(ll j=2;j<=n;j++)
            {
                if(!prime[j])
                {
                    ll numm=0;
                    while(n&&n%j==0)numm++,n/=j;
                    t[j]=max(t[j],numm);
                }
            }
        }
    }
    if(num==0)printf("-1\n");
    else
    {
        ll ans=1;
        for(int i=2;i<=30000;i++)if(t[i])
        {
            ans=ans%mod*poww(i,t[i])%mod;
        }
        printf("%lld\n",ans);
    }
    return 0;
}

K-小红的真真假假签到题题

小红拿到了一个正整数\(x\),她想构造一个正整数\(y\)使得:\(1、\)\(y\)是\(x\)的倍数且\(y\)不等于\(x\);\(2、\)\(x\)在二进制表示下是\(y\)在二进制表示下的一个字串且在二进制表示下\(1\)的个数不同;\(3、\)\(y\)为不超过\(10^{19}\)的正整数。\((1\leq x\leq10^9)\)

思路

我们可以拿\(5\)举例,\(5\)的二进制表示为\(101\),而\(101101\)能作为\(5\)的\(y\),也就是\(101*1001=5*9=45\),因此我们得出,\(y=x*(1+(1<<len(x)))\),其中\(len(x)\)代表\(x\)的二进制表示的长度。

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

int main()
{
    ll x;
    scanf("%lld",&x);
    int len;
    for(int i=30;i>=0;i--)if(x&(1ll<<i)){len=i+1;break;}
    ll mul=1+(1ll<<len);
    printf("%lld\n",x*mul);
    return 0;
}

L-在这冷漠的世界里光光哭哭

有一个字符串\(S\),\(q\)组询问,每次问在区间\([l,r]\)中有多少个长度为\(3\)的字符串\(s\)的子序列。\((1\leq n\leq80000,1\leq q\leq500000)\)

由于还不是很会,就只能参考solemntee大佬的题解

标签:leq,int,ll,long,牛客,2022,ans,集训营,mod
来源: https://www.cnblogs.com/Jerry-Black/p/15874684.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有