题意:
给一个01串s,统计其中长度从A到B的各个子串出现的次数,输出频率最高的N个
十分朴素且无脑地过了...还很快
对于A到B的每个长度len,取出s中所有该长度的串,转化为二进制x,++cnt[len][x],
再作为node放到ans数组中,node有三个成员,val, len, cnt(值,长度,出现次数)
对ans排序,再输出即可
再就是,输入输出稍微注意一点
AC代码如下:
/*
PROB:contact
LANG:C++
ID:fan_0111
*/
#include <cstdio>
#include <algorithm>
struct node { int len, cnt, val; }ans[10010];
bool cmp(node a, node b) {
if (a.cnt == b.cnt) {
if (a.len == b.len) return a.val < b.val;
return a.len < b.len;
}
return a.cnt > b.cnt;
}
int cnt[13][10010];
char ch[200020];
void print(int len, int x) {
// printf("\n%d %d\n", len, x);
char ret[len + 1] = "";
ret[len] = '\0';
int i = len - 1;
while (x) {
ret[i--] = x % 2 + '0';
x /= 2;
}
for (int j = i; j >= 0; --j) ret[j] = '0';
printf("%s", ret);
}
using namespace std;
int main() {
freopen("contact.in", "r", stdin);
freopen("contact.out", "w", stdout);
int a, b, n;
scanf("%d%d%d\n", &a, &b, &n);
int len = 0;
while (scanf("%c", &ch[len]) != EOF) {
if (ch[len] == '\n') continue;
++len;
}
b = len < b ? len : b;
// printf("%c\n", ch[0]);
// printf("%d\n", len);
// ch[len++] = '\0';
// printf("%s\n", ch);
for (int i = a; i <= b; ++i) {
for (int s = 0; s <= len - i; ++s) {
int t = s + i, x(0);
for (int k = s; k < t; ++k) {
x = x * 2 + ch[k] - '0';
}
++cnt[i][x];
}
}
int tot(0);
for (int i = a; i <= b; ++i) {
for (int j = 0; j < (1 << i); ++j) {
if (cnt[i][j]) {
ans[tot].len = i; ans[tot].cnt = cnt[i][j]; ans[tot++].val = j;
}
}
}
sort(ans, ans + tot, cmp);
// for (int i = 0; i < tot; ++i) {
// printf("%d %d %d\n", ans[i].len, ans[i].val, ans[i].cnt);
// }
printf("%d\n", ans[0].cnt);
print(ans[0].len, ans[0].val);
int prev = ans[0].cnt, ln = 1, N(1);
for (int i = 1; i < tot; ++i) {
if (ans[i].cnt != prev) {
++N; if (N == n + 1) break;
printf("\n%d\n", ans[i].cnt);
print(ans[i].len, ans[i].val);
prev = ans[i].cnt;
ln = 1;
continue;
}
if (ln % 6 == 0) printf("\n"); else printf(" ");
print(ans[i].len, ans[i].val);
++ln;
}
printf("\n");
return 0;
}
后来看题解
看到两种想法
1. 解析原串获取子串时,
- 边读入边计算。 设置极限掩码为limit=(1<<(B))-1; //2的B此次方-1
- 每读入一个二进制数0或1,令unsigned int数字串str=((str<<1)+c) & limit;
- 然后扫描str,从末尾向前扫描i=(A到B)位,把所得的数字串t最高位添加1,以区别有前导0的串,例如001和01,添加后变为1001和101
- mask=(1<<i)-1;
- mask2=mask+1;
- t=(S & mask) | mask2;
- 用哈希表记录t的频率 hash[t]++;
(出自 http://blog.csdn.net/damonhao/article/details/19975423)
2. 存储时,使用二叉树
#define LEF(x) (2*(x)+1)
#define RIG(x) (2*(x)+2)
int i, j, idx;
for(i = 0; i < len; i++)
{
idx = 0;
for(j = 0; j < b; j++)
if(i+j < len)
{
if(s[i+j] == '0')
idx = LEF(idx);
else
idx = RIG(idx);
trie[idx]++;
}
}
(出自
http://www.nocow.cn/index.php/Code:USACO/contact/C)