1.子串分值
法一:滑动窗口
O(n^2)超时
#include <iostream>
#include <cstring>
using namespace std;
const int N=1e5+10;
int res[N];
int st[27];
char str[N];
int main()
{
cin>>str+1;
int len=strlen(str+1);
long long ans=0;
for(int i=1;i<=len;i++){
res[i]=1;
st[str[i]-'a']++;
ans+=res[i];
for(int j=i+1;j<=len;j++){
st[str[j]-'a']++;
if(st[str[j]-'a']==1){
res[i]++;
}else{
if(st[str[j]-'a']==2)res[i]--;
}
ans+=res[i];
//printf("i==%d j==%d res=%d\n",i,j,res[i]);
}
for(int j=i+1;j<=len;j++)st[str[j]-'a']--;
st[str[i]-'a']--;
}
printf("%lld",ans);
return 0;
}
法二:
记录每个字母上一次pre和下一次next出现位置,则在此区间内(pre,next)的所有字符由于str[i]的存在要加1
#include <iostream>
#include <cstring>
using namespace std;
const int N=1e5+10;
char str[N];
int pre[N];
int nt[N];
int now[N];
int main(){
cin>>str+1;
int len=strlen(str+1);
for(int i=0;i<26;i++)now[i]=0;
for(int i=1;i<=len;i++){
int c=str[i]-'a';
pre[i]=now[c];
now[c]=i;
}
for(int i=0;i<26;i++)now[i]=len+1;
for(int i=len;i>=1;i--){
int c=str[i]-'a';
nt[i]=now[c];
now[c]=i;
}
long long ans=0;
for(int i=1;i<=len;i++){
ans+=(long long)(nt[i]-i)*(i-pre[i]);
}
printf("%lld",ans);
return 0;
}
2.小数第n位
#include <iostream>
using namespace std;
int quickmi(int a,int b,int mod){
int res=1;
while(b){
if(b&1)res=res*a%mod;
a=a*a%mod;
b>>=1;
}
return res;
}
int main()
{
int a,b,n;
scanf("%d%d%d",&a,&b,&n);
//直接循环n+2次会超时,这里选择用快速幂加速
a=a*quickmi(10,n-1,b)%b;
for(int i=0;i<=2;i++){
a*=10;
printf("%d",a/b);
a=a%b;
}
return 0;
}