先上题目:
Xenia is an amateur programmer. Today on the IT lesson she learned about the Hamming distance.
The Hamming distance between two strings s = s1s2... sn and t = t1t2... tn of equal length n is value . Record [si ≠ ti] is the Iverson notation and represents the following: if si ≠ ti, it is one, otherwise — zero.
Now Xenia wants to calculate the Hamming distance between two long strings a and b. The first string a is the concatenation of n copies of string x, that is, . The second string b is the concatenation of m copies of string y.
Help Xenia, calculate the required Hamming distance, given n, x, m, y.
The first line contains two integers n and m (1 ≤ n, m ≤ 1012). The second line contains a non-empty string x. The third line contains a non-empty string y. Both strings consist of at most 106 lowercase English letters.
It is guaranteed that strings a and b that you obtain from the input have the same length.
Print a single integer — the required Hamming distance.
Please, do not use the %lld specifier to read or write 64-bit integers in С++. It is preferred to use the cin, cout streams or the %I64dspecifier.
100 10
a
aaaaaaaaaa
0
1 1
abacaba
abzczzz
4
2 3
rzr
az
5
In the first test case string a is the same as string b and equals 100 letters a. As both strings are equal, the Hamming distance between them is zero.
In the second test case strings a and b differ in their 3-rd, 5-th, 6-th and 7-th characters. Thus, the Hamming distance equals 4.
In the third test case string a is rzrrzr and string b is azazaz. The strings differ in all characters apart for the second one, the Hamming distance between them equals 5.
题意:给出两个串的循环节以及循环次数,求这两个串的汉明距离,这里的汉明距离指的是对应位置的字符如果不一样就是加1。
这里的数据有点大,循环节的长度就有10^6,循环次数最大10^12,所以不能直接暴搜。这里的做法是先求出两个循环节的最小公倍数l和最大公约数g。然后统计面每个字符串某个位置i是哪个字符,同时保存在i%g的位置,因为在一个l的范围里面只有在g的倍数的位置两个字符串的字符才会有比较,然后统计一下l的范围里面两个字符串每一个位置的不同的字符的对数。然后因为最大公约数l的距离以后字符串的异同又会和前面一样,所以我们只要再乘以一个字符串的总长度对于l的倍数就可以了。
但是这里需要优化,因为比较同一个位置的字符异同的时候比较次数是26*26-26如果再乘上g的话有可能会非常大,这样就会超时,所以我们需要考虑它的反面,我们可以用一个字符串的总长度剪去位置上有相同字符的数量,这样我们就可以减少一维变成g*26了。
但是这样做可能还是会wa,因为我们还需要 注意到数据大小(10^6)*(10^12)快要到达long long 的极限了,如果我们是先用前面的到的结果ans先乘上这里的数再做后面的除法的话会有溢出的可能,所以我们需要先求了字符串的总长度对于l的倍数,然后再将ans乘以倍数,这样就不会爆long long了。
上代码:
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #define MAX 1000002 5 #define ll long long 6 using namespace std; 7 8 char a[MAX],b[MAX]; 9 ll n,m,r,le; 10 ll la,lb,g,l,ans; 11 int dpa[MAX][26]; 12 int dpb[MAX][26]; 13 14 ll gcd(ll a,ll b){ 15 return b==0 ? a : gcd(b,a%b); 16 } 17 18 19 int main() 20 { 21 //freopen("data.txt","r",stdin); 22 while(scanf("%I64d %I64d",&n,&m)!=EOF){ 23 scanf("%s",a); 24 scanf("%s",b); 25 la=strlen(a); 26 lb=strlen(b); 27 g = a>b ? gcd(la,lb) : gcd(lb,la); 28 l=la*lb/g; 29 memset(dpa,0,sizeof(dpa)); 30 memset(dpb,0,sizeof(dpb)); 31 for(int i=0;i<la;i++){ 32 dpa[i%g][a[i]-'a']++; 33 } 34 for(int i=0;i<lb;i++){ 35 dpb[i%g][b[i]-'a']++; 36 } 37 ans=0; 38 for(int i=0;i<g;i++){ 39 for(int j=0;j<26;j++){ 40 ans+=(ll)dpa[i][j]*(ll)dpb[i][j]; 41 } 42 } 43 ans=n*la/l*ans; 44 ans=n*la-ans; 45 printf("%I64d ",ans); 46 } 47 return 0; 48 }