目录
1、子串分值(20年省赛)
解析:
用到尺取法(双指针),只要用指针找到相同的数的左右边界的位置以及当前数的位置,然后计算各个字母的贡献度并相加,即可求出答案。
比如ababc中a在a、ab中有贡献,即为2=(0-(-1))*(2-0),b在ab、aba、b、ba中有贡献,即4=(1-(-1))*(3-1)……所以公式是(当前位置 - 左边与其相同字符且靠的最近的位置)*(左边与其相同字符且靠的最近的位置 - 当前位置)
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long LL;
string s;
LL sum;
int main() {
cin>>s;
for(int i=0; i<s.size(); i++) {
char h=s[i];//标记该字符,找出左右边界
int left,right;
for(right=i+1; right<s.size(); right++)//右边界的相同点
if(s[right]==h) break;
for(left=i-1; left>=0; left--)//左边界的相同点
if(s[left]==h) break;
sum+=(i-left)*(right-i);
}
cout<<sum;
return 0;
}
同年类似题:
解析:同上,只需要改一下贡献度即可,依然是用指针找到相同数的位置,不过这次不需要两个指针来找左右边界,只需要一个指针找到之前的边界位置即可。
比如:ababc的a在字串a、ab、aba、abab、ababc都有贡献,即5=5*1;b在ab、aba、abab、ababc、b、ba、bab、babc,即8=4*2;第二个a在ba、bab、babc、a、ab、abc,即6=3*2;第二个b在ab、abc、b、bc,即4=2*2;c在ababc、babc、abc、bc、c,即5=1*5
所以可得公式(当前位置-左边与当前字符相同且靠得最近的位置)*(字串总长-当前位置)
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long LL;
LL sum;
string s;
int main() {
cin>>s;
int left;
for(int i=0; i<s.size(); i++) {
char c=s[i];
for(left=i-1; left>=0; left--)
if(c==s[left]) break;//找到左边相同点的位置
sum+=(i-left)*(s.size()-i);
}
cout<<sum;
return 0;
}
2、小数第n位(17年国赛)
解析:
快速幂模板题,注意配出3位整数用于输出,我们还没推出公式时,可以得出(a*quick(10,n+2))/b%1000,用案例来说就是1000/8%1000=125(可以获得125),我们知道快速幂中需要%1个数才能保证不爆精度,所以这题同理,那么取模的这个数该咋找?我们将上式写成(x/y)%1000,模1000即取后三位数,设这个数为z,即(x/y)%1000=z。假如我们改成数,(10000/4)%1000=500,我们猜测一下两边同乘4就是10000%(4*1000)=500*4,发现是成立的,所以我们将上面的式子改为x % (y * 1000) = y * z(我也不知道为什么),然后%的数就是(y * 1000),这道题就大功告成了。
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long LL;
LL a,b,n;
LL quick(LL x,LL y) {
LL ans=1;
while(y>0) {
if(y&1) ans=(ans*x)%(b*1000);
x=(x*x)%(b*1000);
y/=2;
}
return ans;
}
int main() {
cin>>a>>b>>n;
cout<<(LL)((a*quick(10,n+2))%(b*1000)/b);//后面改成/b%1000也行
return 0;
}