2022牛客寒假算法基础集训营4
A-R
长度为的字符串,只包含大写字母,问有多少段连续子串能满足包含至少个“”且不包含“”。
思路
由于不要“”,所以就很容易想到在每一段没有“”的串中尺取,然后就结束了。
代码
#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-进制
长度为的字符串,组操作,每次输入个整数。若为,则将第个数字改为;若为,查询区间所能表示某进制的最小值(进制必须合法且在二进制到十进制之间,可包含前导0),对取模。
思路
敲十棵线段树应该就能解决问题了吧(逃
代码
#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-蓝彗星
有颗星,每颗星在天中保留秒,代表第颗星的颜色,“”代表蓝色,“”代表红色,代表的颗星出现的时间,假设黑夜无限长,问能看到蓝色彗星且看不到红色彗星的时长。
思路
对于这样的题目应该一下就能想到差分,一想到差分应该就直接结束了吧……
代码
#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-雪色光晕
小红初始位置为,她每秒有一个方向向量,会沿着该方向跑一秒,小红想知道他在跑步过程中距离小果的最近距离。
思路
这个问题就是判断线段外一点到线段的最短距离是等于到直线的距离还是到端点的距离,然后稍微运用一下高中知识就能轻松了。
代码
#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); } 对于给定的,问是多少。
代码
第一道签到题,但是一开始有点慌,规律找错了,哭死。所以其实就是一道输入输出题。
代码
#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-小红的记谱法
思路
这题应该就是一道很简单的模拟题吧……
代码
#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-子序列权值乘积
规定一个数组的权值为最大值乘上最小值。小红有一个数组,问这个数组的所有非空子序列的权值之积对取模后的答案是多少。
思路
首先应该就能想到对这个序列排个序,然后对于一个数,他前面有个数,后面有个数,那么他就有的次方的机会可以成为最大值,最小值也同理,然后差不多就能结束了,不过还要知道一个芝士点叫做欧拉降幂:
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-真真真真真签到题
小红和小紫在一个正方体中,小紫在正中间,小红在角落,两人相距,问正方体的体积。
思路
第二道签到题,没什么难度吧应该……
代码
#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-爆炸的符卡洋洋洒洒
有张符卡,每张符卡的魔力消耗为,威力为。小红要保证发出的符卡的魔力消耗之和为的倍数,问能够发出的最大威力是多少。
思路
首先想到的当然是背包,但是当然是存不下的,但是由于的值不大,所以直接存模后的值就能轻松解决啦。
代码
#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-区间合数的最小公倍数
小红有两个整数,问中所有合数的最小公倍数是多少,答案对取模。
思路
这道题我一开始理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-小红的真真假假签到题题
小红拿到了一个正整数,她想构造一个正整数使得:是的倍数且不等于;在二进制表示下是在二进制表示下的一个字串且在二进制表示下的个数不同;为不超过的正整数。
思路
我们可以拿举例,的二进制表示为,而能作为的,也就是,因此我们得出,,其中代表的二进制表示的长度。
代码
#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-在这冷漠的世界里光光哭哭
有一个字符串,组询问,每次问在区间中有多少个长度为的字符串的子序列。
思路
当然能想到运用的思想,表示“”在前个位置的时候子序列“”的个数,表示前个字母中子序列“”的个数,表示前个字母中子序列“”的个数,表示后个字母中子序列“”的个数。然后要求区间中子序列“”的个数,我们就先二分找到区间中第一个“”的前一个位置和最后一个“”的位置,就能得到,当然这还不是答案,我们要减去一些非法的答案:。然后区间中子序列“”的答案也是同理。怕我讲的不清楚,特此附上大佬的题解。
代码
#include<bits/stdc++.h> using namespace std; typedef long long ll; char s[80005]; ll dp1[80005][26][26]; ll tmp[26][26][26]; ll dp2[80005][26][26]; ll dp3[80005][26]; ll dp4[80005][26]; vector<int>id[26]; int main() { int n,q; scanf("%d%d",&n,&q); scanf("%s",s+1); for(int i=0;i<26;i++)id[i].push_back(0); for(int i=1;i<=n;i++) { id[s[i]-'a'].push_back(i); for(int j=0;j<26;j++)dp3[i][j]=dp3[i-1][j]; dp3[i][s[i]-'a']++; for(int j=0;j<26;j++) { for(int k=0;k<26;k++) dp2[i][j][k]=dp2[i-1][j][k]; dp2[i][j][s[i]-'a']+=dp3[i-1][j]; } } for(int i=n;i>=1;i--) { for(int j=0;j<26;j++)dp4[i][j]=dp4[i+1][j]; dp4[i][s[i]-'a']++; } for(int i=1;i<=n;i++) for(int j=0;j<26;j++) for(int k=0;k<26;k++) dp1[i][j][k]=tmp[s[i]-'a'][j][k]+=dp3[i-1][j]*dp4[i+1][k]; while(q--) { int l,r; char str[4]; scanf("%d%d%s",&l,&r,str+1); int x=str[1]-'a',y=str[2]-'a',z=str[3]-'a'; if(dp3[r][y]-dp3[l-1][y]==0){printf("0\n");continue;} int l1=lower_bound(id[y].begin(),id[y].end(),l)-id[y].begin(); int r1=upper_bound(id[y].begin(),id[y].end(),r)-id[y].begin(); ll ans=dp1[id[y][r1-1]][x][z]-dp1[id[y][l1-1]][x][z];//"y"在[l,r]中 ll ans1=dp2[r][y][z]-dp2[l-1][y][z]-dp3[l-1][y]*(dp3[r][z]-dp3[l-1][z]);//"yz"在[l,r]中 ll ans2=dp2[r][x][y]-dp2[l-1][x][y]-dp3[l-1][x]*(dp3[r][y]-dp3[l-1][y]);//"xy"在[l,r]中 ans-=dp3[l-1][x]*ans1;//减去"x"在[1,l-1],"yz"在[l,r]的情况 ans-=dp4[r+1][z]*ans2;//减去"xy"在[l,r],"z"在[r+1,n]的情况 ans-=dp3[l-1][x]*(dp3[r][y]-dp3[l-1][y])*dp4[r+1][z];//减去"x"在[1,l-1],"y"在[l,r],"z"在[r+1,n]的情况 printf("%lld\n",ans); } return 0; }
__EOF__

本文链接:https://www.cnblogs.com/Jerry-Black/p/15874684.html
关于博主:小蒟蒻一只( ̄^ ̄)ゞ
版权声明:转载请注明来源哟~ QAQ
声援博主:UP UP UP !!!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET10 - 预览版1新功能体验(一)