标签:
照例传送门CNUOJ - 0385:http://oj.cnuschool.org.cn/oj/home/problem.htm?problemID=355
题目分析:首先感谢”数据结构与算法“群群友的支持与鼓励,没有你们的点拨&鼓励我不可能搞出来的。
这道题如果是暴力枚举循环节的话,可能数据会坑你一下……(只有一个循环节即两数互质= =)那就挂了……暴力好像也能拿30分吧。
这道题算法的雏形是Kael大神弄出来的,他是这么跟我说的:
假设是|T|>|S|,因为|A|=|B|,所以S与T的比较周期有|T|个,再检查S中的每个字符与T中字符不一样的个数,就得到所有周期比较完后的个数,然后把S中每个字符的个数加起来就是答案,如果|A|大于了|T|和|S|的最小公倍数,就把答案乘以M/|T|,M/|T|又是新一轮周期。
为什么S与T的比较周期有|T|个呢?通俗的说就是S中的每个字符都会跟T中的每个字符进行对位一次,而再次当S第一个字符与T第一个字符对位时,就是进行了|T|个周期了。
看不懂是吧?知道你也不会好好看,我来给你分析一下= =
比如这两个长度互质的串:
把长度标上后,让我们关注一下S串头元素进行了哪几次比较:
可以看到共有4次比较(用深绿色圆圈表示),我们发现这不就是T串里的4个元素吗?
好,那我们看看在T串上S的头元素是怎么比较的:
上面四个是S串,底下的是T串。我们来举一个例子:
所以说头元素贡献了3份答案。
那么显而易见,不仅S串头元素会全都比较T串的四个元素,第二个、第三个元素也会比较,我们再画一个清晰的图:
上面是S串,下面是T串,先让上面最左边的”a“进行一次全部比较,可以看到有2个答案。
第二个元素同理有三个答案。
第三、第四个S串里的”a“元素答案一定和answer1是一样的(想一想,为什么?)
最后根据加法、乘法原理,答案应该是:3 * answer1 + 1 * answer2 = 3 * 2 + 1 * 3 = 9;
画回最原始的图再看一眼:
答案正确。此输入应该是:5 4 abaa abbaa 输出是:9
那如果输入的是10 8 abaa abbaa呢?
那么就应该有两个循环节了,答案是18。
那么至此为止,两字串长度互质的情况我们已经会算了,可以用两个哈希表vis_S[27], vis_T[27]分别表示26个小写字母在S串和T串中分别出现了几次。
程序不难写出,建议读者好好看一眼哈希表的使用,为下边打好基础:
1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 using namespace std; 5 6 void read(int& x) 7 { 8 x = 0; 9 int sig = 1; 10 char ch = getchar(); 11 12 while(!isdigit(ch)) 13 { 14 if(ch == ‘-‘) sig = -1; 15 ch = getchar(); 16 } 17 18 while(isdigit(ch)) 19 { 20 x = x * 10 + ch - ‘0‘; 21 ch = getchar(); 22 } 23 24 return ; 25 } 26 27 int tot; 28 29 long long ans; 30 31 const int maxn = 1000000 + 10; 32 33 char S[maxn], T[maxn]; 34 int T1, T2; 35 36 int vis[2][27]; 37 38 int read_str1() 39 { 40 char tmp = getchar(); 41 42 while(!isalpha(tmp)) tmp = getchar(); 43 44 tot = 0; 45 46 while(isalpha(tmp)) 47 { 48 S[tot++] = tmp; 49 50 vis[0][tmp - ‘a‘]++; 51 52 tmp = getchar(); 53 } 54 55 S[tot] = ‘\0‘; 56 return tot; 57 } 58 59 int read_str2() 60 { 61 char tmp = getchar(); 62 63 while(!isalpha(tmp)) tmp = getchar(); 64 65 tot = 0; 66 67 while(isalpha(tmp)) 68 { 69 T[tot++] = tmp; 70 71 vis[1][tmp - ‘a‘]++; 72 73 tmp = getchar(); 74 } 75 76 T[tot] = ‘\0‘; 77 return tot; 78 } 79 80 void vis_init() 81 { 82 long long tmp; 83 84 for(int i = 0; i < 27; i++) 85 { 86 tmp = 0; 87 for(int j = 0; j < 27; j++) 88 { 89 if(i == j) continue; 90 tmp += vis[1][j]; 91 } 92 ans += vis[0][i] * tmp; 93 } 94 95 return ; 96 } 97 98 int main() 99 { 100 read(T1); 101 read(T2); 102 103 int s1 = read_str1(); 104 int s2 = read_str2(); 105 106 vis_init(); 107 108 ans = (long long)((double)ans * ((double)T1 / (double)s2)); 109 //记得是同时约了一个s1 110 111 printf("%lld\n", ans); 112 113 return 0; 114 }
好,那么我们来看看非互质的情况:
标签:
原文地址:http://www.cnblogs.com/chxer/p/4322080.html