B 武辰延的字符串
1.题目
2.题意
求多少个s串的前缀组合能构成t的前缀
3.思路
字符串哈希 + 二分
用哈希存储s的所有前缀,枚举前缀:
第 i+1个 二分查找最大的满足去掉si前缀的剩下的串和s匹配的最大前缀
比如:
s = “abaabc”
t = “ababaabb”
s串和t串的前两个都相同,此时i为2,那么t - “ab” = “abaabb”
开始二分查找最大的s与t的匹配的前缀,可以看出是abaab。
4.代码
#include <iostream>
#include <cstring>
using namespace std;
typedef unsigned long long ULL;
const int P = 131, Q = 100010, N = 100010;
const int mod = 1e9 + 7;
int n1, n2;
ULL sum1[N], sum2[N], p[N]; //存前缀和
char s[N], t[N];
ULL get1(int l, int r){
return sum1[r] - sum1[l - 1]* p[r - l + 1];
}
ULL get2(int l, int r){
return sum2[r] - sum2[l - 1]* p[r - l + 1];
}
int main(){
//读入
scanf("%s", s + 1);
scanf("%s", t + 1);
n1 = strlen(s + 1);
n2 = strlen(t + 1);
//初始化
sum1[0] = sum2[0] = 0;
p[0] = 1;
for(int i = 1; i <= n1; ++ i)
sum1[i] = sum1[i - 1] * P + s[i];
for(int i = 1; i <= n2; ++ i)
sum2[i] = sum2[i - 1] * P + t[i], p[i] = p[i - 1] * P;
//计算答案
ULL ans = 0;
for(int i = 1; i < n2 ; ++ i){
if(s[i] != t[i]) break;
int l = 1, r = n1, tmp = 0;
while(l <= r){
int mid = l + r >> 1;
ULL t1 = get1(1, mid);
ULL t2 = get2(i + 1, i + mid);
if(t1 == t2) tmp = mid, l = mid + 1;
else r = mid - 1;
}
ans += tmp;
}
printf("%llu\n", ans);
return 0;
}
J 邬澄瑶的公约数
题目
输入
2
9 3
1 2
输出
9
题意:
求gcd(a1^b1, a2 ^b2, a3 ^b3, …, an ^bn)
思路:
- 暴力: 由于bi <= 1e4太大, 不好求。
- 我们可以把每个ai分解质因数,求每个质因数最小的次数,最后乘起来即可
AC代码:
#include <iostream>
#include <cstring>
#include <string>
using namespace std;
typedef long long LL;
const int mod = 1e9 + 7, N = 10005;
int n;
int a[N], b[N], f[N];
int p[N], cnt;
bool st[N];
void Prime(int n){ //素数筛筛出素数
for(int i = 2; i <= n; ++ i){
if(!st[i]) p[cnt ++] = i;
for(int j = 0; p[j] <= n / i; ++ j){
st[p[j] * i] = true;
if( i % p[j] == 0) break;
}
}
}
LL qp(LL a, LL b){ //快速幂
LL res = 1;
while(b){
if(b&1) res = res * a % mod;
b >>= 1;
a = a * a % mod;
}
return res;
}
int main(){
Prime(N);
memset(f, 0x3f, sizeof f); //f:存储最小的次方
scanf("%d", &n);
for(int i = 0; i < n; ++ i) scanf("%d", a + i);
for(int i = 0; i < n; ++ i) scanf("%d", b + i);
for(int i = 0; i < n; ++ i){
int x = a[i], y = b[i];
for(int j = 0; j < cnt; ++ j){ //分解质因数
int c = 0; //c保存该质因数的次方数
if(x % p[j] == 0)
while(x % p[j] == 0) x /= p[j], c ++;
c = c * y; //因为是x^y, 所以次方要乘bi
f[j] = min(f[j], c); //维护最小次方数组
}
}
LL sum = 1;
for(int i = 0; i < cnt; ++ i)
sum = (sum * qp(p[i], f[i])) % mod; //计算结果
printf("%lld\n", sum);
return 0;
}