B:
思路:
原文链接: 2024牛客寒假算法基础集训营5-个人题解 - 知乎
既然不能删除连续的字符,那么就只有"mygo","m_ygo","my_go","myg_o","m_y_go","m_yg_o","my_g_o","m_y_g_o"这8种子串能够通过删除得到"mygo";
那么我们就只需要寻找这八种子串的数量。对于匹配的子串,子串内部的删除方式是唯一确定的,因此现在需要考虑子串外删除的方式有多少种:只需要分别求左边删的方式数和右边删的方式数,再相乘即可得。
至于怎么求删除方式的种数,我们考虑对于任意一个长度为n字符串,由于不能连续删除,我们这里使用dp,简单思考易知转移方程为dp[i]=dp[i-1]+dp[i-2],其中dp[i]表示长度为i的字符串有多少种删除方式(发现这就是个斐波那契数列)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int M=1e9+7;
ll f[200005];
bool check(string s1,string s2){
for(int i=0;i<s1.size();i++){
if(s1[i]=='x')continue;
else{
if(s1[i]!=s2[i]) return 0;
}
}
return 1;
}
int main(){
cin.tie(0);cout.tie(0);
ios::sync_with_stdio(0);
string s;
cin>>s;
int n=s.size();
f[0]=1;f[1]=2;
for(int i=2;i<=n;i++){
f[i]=(f[i-1]+f[i-2])%M;//f[i]表示长度为i的字符串有多少删除方式
}
s="1"+s+"00000000000000";//不能从i=0开始不然f中的下标会出现负号
ll sum=0;
vector<string>str={"mygo","mxygo","myxgo","mygxo","mxyxgo","myxgxo","mxygxo","mxyxgxo"};
for(int i=1;i<n;i++){
for(auto &j:str){
auto x=s.substr(i,j.size());//从i开始长度为j.size()的字符串s的子串
// cout<<x<<endl;
if(check(j,x)){
sum=(sum+f[i-1]*f[n-(i+j.size())+1])%M;//计算符合条件之外删除字母的种数
}
}
}
cout<<sum<<"\n";
return 0;
}
C:
思路:就是数组中某个数x左右两边补零的个数不能超过x-1个
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,m,k,t;
signed main(){
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
int a=0x3f3f3f3f,b,ans=0;
cin>>n;
for(int i=1;i<=n;i++){
cin>>b;b--;
ans+=min(a,b);//表示与前一个数之间的0的数目,指i的左边
a=b-min(a,b);//表示去除左边给的0的个数后,剩下的是给右边的贡献值
}
cout<<ans+a<<endl;
return 0;
}
G\H:
思路:挺明确的,1-n,输出pi+i(i-n)都为质数的序列
// i 1
//pi 2
// i 1 2
//pi 2 1
//i 1 2 3
//pi 1 3 2
//i 1 2 3 4
//pi 4 3 2 1
//i 1 2 3 4 5
//pi 1 5 4 3 2
//i 1 2 3 4 5 6
//pi 6 5 4 3 2 1
//i 1 2 3 4 5 6 7 n=7
//pi 1 3 2 7 6 5 4
//根据规律,我们只需要找到距离n最近的那个质数
//从1开始,依次计算n+1,n+2,n+3....直到成为质数
//找到这个i,这个i之后的就依次对应n,n-1,n-2
#include<iostream>
using namespace std;
const int N = 1e6+10;
int ans[N];
bool check(int x){
for(int i=2;i<=x/i;i++){
if(x%i==0)return false;}
return true;
}
int main()
{
int n;
cin>>n;
int j=1;
int x=n;
int p=n;
while(x)
{
while(!check(n+j))
j++;
for(j;j<=n;j++)
ans[j]=x--;
n=x;
j=1;
}
for(int i=1;i<=p;i++)
cout<<ans[i]<<" ";
return 0;
}
I:
这个也挺清晰的,注意的点是当a与t各在0的两边时,若k看照到a的位置时sum+=2*abs(a)+t(先去到a的地点再去t的地点),若不行,则先去t点,则sum+=3*abs(a)+2*abs(t);
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e5+10;
signed main()
{
cin.tie(0);
cout.tie(0);
int t,a,k;
cin>>t>>a>>k;
int sum=0;
if(a>=0&&t>=0)
{
if(a>=t) sum+=abs(t)+2*abs(a-t);
else sum+=abs(t);
}
else if(a<0&&t<0)
{
if(a<=t)sum+=abs(t)+2*abs(a-t);
else sum+=abs(t);
}
else if((a>=0&&t<0)||(a<0&&t>=0))
{
if(abs(k)>=abs(a)) sum+=2*abs(a)+abs(t);
else sum+=3*abs(t)+2*abs(a);
}
cout<<sum<<endl;
}