51NOD欧姆诺姆和项链——KMP算法(非水题)
思路:好久不见,今天要开始真正写题了。这个题之前我的理解有点问题,导致写了很久最终都是一直都只能过样例。需要注意的是输出中每一个“1”都是和别的输出相互独立的,比如输入以下样例
输入样例: 8 2 abababab 输出样例: 00011101
在输出字符串当中每一个“1”都代表原字符串中该位置以前包括该位置的字符都是满足题目要求的ABAB或ABABA类型。
刚开始没有理解好以上,导致我错误的理解是既然都能找到既然都是ABABA类型了,那肯定也是前缀也是ABAB,那我只需要找前缀为ABAB类型的就行啊。所以,而且我之前的输出一直都是前面一直为0后段一直为1。所以说样例也是有点坑,完全符合我了错误的思路。
以下内容参照了这里 》》LuYouQi233《《
这里用到了KMP算法当中的next数组,我们用S来表示一个循环节(比如字符串abababab中,ab是一个循环节S),在next数组中的值除了表示最长相等前后缀以外,在这个题目中还能表示有多少个AB;当有空字符串的时候我们用ABAB来代表这个字符串,否则用ABABA。
num = (i+1)/(i-next[i])表示当前字符串中有多少个AB;num/k 表示当前AB中有多少个S;num%k 表示当前的A中有多少个S;
1)当(i+1)%(i-next[i])==0时,既当前字符串的类型是ABAB型;所以num/k大于等于num%k既满足条件输出1;
2)当(i+1)%(i-next[i])!=0时。既当前的字符串类型是ABABA型;所以需要num/k大于num%k既满足条件输出1;
那么问题来了,为什么一个是大于等于一个是等于呢??因为第一种情况是B可能是空的,而第二种情况A或B都不能为空。
#include<cstdio> #include<iostream> using namespace std; int nextt[1000100]; char s[1000100]; void cal_next(char str[],int len) { nextt[0] = -1; int k = -1; for (int i = 1; i < len; i++){ while (k > -1 && str[k + 1] != str[i]) k = nextt[k]; if (str[k + 1] == str[i]) k += 1; nextt[i] = k; } } int main() { int n, k; cin >> n >> k; getchar(); for (int i = 0; i < n; i++){ s[i] = getchar(); } cal_next(s, n); for (int i = 0; i < n; i++){ int num = (i + 1) / (i - nextt[i]); if ((i+1) % (i - nextt[i])==0){ if (num / k >= num%k) cout << "1"; else cout << "0"; }else{ if (num / k > num%k) cout << "1"; else cout << "0"; } } return 0; }