T1.子串分值和
思路:
硬做的话会超时,参考大佬的思路用所谓‘贡献度’来思考
我们可以计算每个字符的贡献,并计算他们的贡献和。怎么计算贡献呢?因为区间内重复的字符只算一个,所以对于样例ababc中第一个a字母来说,它能被计数的情况就是从上一个字母a开始(因为没有所以实际上是从它开始),区间长度从1到len的len种情况(虽然到第3个位置也有个字符a,但我们只记录一个,所以记录的还是最先出现的a),那么第一个字母a所能提供的贡献一共就是len,即5。我们再看第二个字母a,和前面说的一样,他能被计数的情况,就是从上一个相同的字母开始,枚举区间长度直到到达字符串末尾,所以第二个字母所能提供的贡献就是:(当前字母位置 - 上一个相同字母)*(区间长度 - 当前字母位置)=2 *3=6;我们只要如法炮制,求得所有字符的贡献,并把计算贡献的总和即可。
代码:
#include<bits/stdc++.h>
using namespace std;
string s;
long long ans,last[26];
int main()
{
memset(last,-1,sizeof(last));//为了第一个
cin>>s;
int n=s.size();
for(int i=0;i<n;i++)
{
ans+=(i-last[s[i]-'a'])*(n-i);
last[s[i]-'a']=i;
}
cout<<ans;
}
T2.循环字串
思路:
只需要把给的字串跟自己相加,再把原来的字串反转,判断是否是相加后新字符串的字串
代码:
#include<bits/stdc++.h>
using namespace std;
int n,t;
string s;
int main()
{
cin>>t;
while(t--)
{
bool flag=true;
cin>>n>>s;
string s1=s,s2=s+s;
reverse(s1.begin(),s1.end());
int idx=s2.find(s1);//好用的函数
if(idx<0)flag=false;
if(flag)cout<<"YES"<<'\n';
else cout<<"NO"<<'\n';
}
}
T3.整齐的数组
思路:
这个题其实就是找出除了最小值之外,其余值到最小值的距离的最大公约数,求全部的公约数:就是将数组全部遍历一遍即可,得到最后的gcd。除此之外当数组中的数全部相同时gcd为0。
代码:
#include<bits/stdc++.h>
using namespace std;
int n,a[45];
int main()
{
int t;
cin>>t;
while(t--)
{
int ans=0,minn=0x3f3f3f3f;
memset(a,0x3f3f3f3f,sizeof(a));
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
minn=min(a[i],minn);
}
for(int i=1;i<=n;i++)
ans=__gcd(a[i]-minn,ans);
if(ans==0)cout<<-1<<endl;
else cout<<ans<<endl;
}
}
T5.快快变大
思路:
思路类似于蓝桥杯的那题 ‘石子合并’
最主要的dp递推:dp[i][j]=max(dp[i][j],dp[i][k] + dp[k + 1][j] + (cheng[i][k]-cheng[k+1][j])^2),cheng表示i到j乘积,k从i+1递增到i+len-2。
代码:
#include<bits/stdc++.h>
using namespace std;
const int mod=1000003;
long long n,a[305],dp[305][305],mtp[305][305];
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i];
for(int i=1;i<=n;i++)
{
mtp[i][i]=1;
mtp[i][i-1]=1;
for(int j=i;j<=n;j++)
mtp[i][j]=(mtp[i][j-1]*a[j])%mod;//预处理求出前缀积
}
for(int len=2;len<=n;len++)//长度
for(int i=1;i+len-1<=n;i++)//起点
{
int j=i+len-1;//终点
for(int k=i;k<j;k++)//开始枚举
dp[i][j]=max(dp[i][j],dp[i][k]+dp[k+1][j]+(mtp[i][k]-mtp[k+1][j])*(mtp[i][k]-mtp[k+1][j]));
}
cout<<dp[1][n];
}
T6.蒟蒻
思路:
模拟题,按照题目意思一步一步做下来就好啦
代码:
#include<bits/stdc++.h>
using namespace std;
int n,op,w,t,ans,idx;
struct GD
{
int cost;
int val;
}jelly[100005];
bool cmp1(GD a,GD b)
{
return a.cost<b.cost;
}
bool cmp2(GD a,GD b)
{
return a.val<b.val;
}
void cheap()
{
sort(jelly+1,jelly+1+idx,cmp1);
idx--;
for(int i=1;i<=idx;i++)
jelly[i]=jelly[i+1];
}
void bad()
{
sort(jelly+1,jelly+1+idx,cmp2);
idx--;
for(int i=1;i<=idx;i++)
jelly[i]=jelly[i+1];
}
int main()
{
cin>>n;
while(n--)
{
cin>>op;
if(op==1)
{
bool flag=true;
cin>>w>>t;
for(int i=0;i<=idx;i++)
if(jelly[i].cost==w||jelly[i].val==t)
{
flag=false;
break;
}
if(flag)
{
idx++;
jelly[idx].cost=w;
jelly[idx].val=t;
}
}
else if(op==2) cheap();
else bad();
}
for(int i=1;i<=idx;i++)
ans+=jelly[i].cost;
cout<<ans;
}
T7.进制转换
思路:
先转换成十进制来做加法,最后在转化成给定进制输出,可以共两个函数来实现这两个功能
代码:
#include<bits/stdc++.h>
using namespace std;
long long ans=0;
string strans;
long long solve1(int t,string s)
{
long long x=0;
long long k=1;
for(int i=s.length()-1;i>=0;i--)
{
int a;
if(s[i]>='0'&&s[i]<='9') a=s[i]-'0';
if(s[i]>='A'&&s[i]<='Z') a=s[i]-'A'+10;
if(s[i]>='a'&&s[i]<='z') a=s[i]-'a'+36;
x=x+a*k;k*=t;
}
return x;
}
void slove2(long long ans,int m)
{
while(ans)
{
int k=ans%m;
ans/=m;
if(k>=0&&k<=9) strans+='0'+k;
if(k<=35&&k>=10) strans+='A'+(k-10);
if(k<=61&&k>=36) strans+='a'+(k-36);
}
for(int i=strans.length()-1;i>=0;i--)
cout<<strans[i];
}
int main()
{
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++)
{
int t;
string s;
cin>>t>>s;
ans+=solve1(t,s);
}
slove2(ans,m);
}
T9.锦标赛
思路:
这题想到了其实挺简单的。实际上如果有一个能力值a与某一个能力值b满足a>b且差的绝对值大于K,则能力值小于等于b的人都绝对不可能获胜。因为能力值小于等于b的人无论怎么比,最后还是会输给能力值为a的人。因此我们只需要先把能力值升序排序(从左到右依次增大),然后不断在两两之间判断是否差值的绝对值大于K,如果大于K的话,这个能力值大的左边的人全部都标记为不可能获胜。
代码:
#include<bits/stdc++.h>
using namespace std;
int n,k,a[100005];
int main()
{
cin>>n>>k;
int tmp;
for(int i=1;i<=n;i++)
cin>>a[i];
sort(a+1,a+1+n);
for(int i=1;i<n;i++)
{
if(a[i+1]-a[i]>k)
tmp=i;
}
cout<<n-tmp;
}
T10.饿饿,饭饭2
思路:
如果两个数通过乘上多个2和3可以达到相等,那么反过来,这两个数通过除去多个2和3也可以达到相等。而且这个相除后得到的数应该是这两个数之间的最大公约数。
由于不知道除去多个2和除去多个3的先后顺序,需要通过dfs进行回溯搜索
代码:
#include<bits/stdc++.h>
using namespace std;
int t,n,num[200005];
bool dfs(int num,int gcd)
{
if(num<gcd)return false;
bool flag1=false,flag2=false;
if(num%2==0) flag1=dfs(num/2,gcd);
if(num%3==0) flag2=dfs(num/3,gcd);
return flag1||flag2||num==gcd;
}
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
cin>>t;
while (t--)
{
bool flag=true;
memset(num,0x3f3f3f3f,sizeof(num));
cin>>n;
for(int i=1;i<=n;i++)
cin>>num[i];
int gcd=num[1];
for(int i=1;i<=n;i++)
gcd=__gcd(num[i],gcd);//求出这几个数的最大公约数
for(int i=1;i<=n;i++)
if(!dfs(num[i],gcd))//把这个数除去多个2或3判断能不能变成最大公约数
{
flag=false;
break;
}
if(flag)cout<<"YES"<<'\n';
else cout<<"NO"<<'\n';
}
}