Translate:USACO/contact

描述

奶牛们开始对用射电望远镜扫描牧场外的宇宙感兴趣。最近,他们注意到了一种非常奇怪的脉冲调制微波从星系的中央发射出来。他们希望知道电波是否是被某些地外生命发射出来的,还是仅仅是普通的的星星发出的。

帮助奶牛们用一个能够分析他们在文件中记下的记录的工具来找到真相。他们在寻找长度在A到B之间(包含A和B本身)在每天的数据文件中重复得最多的比特序列 (1 <= A <= B <= 12)。他们在找那些重复得最多的比特序列。一个输入限制告诉你应输出多少频率最多的序列。

符合的序列可能会重叠,并且至少出现一次的序列会被计数。


格式

PROGRAM NAME: contact

INPUT FORMAT:

(file contact.in)

第一行: 三个用空格分隔的整数: A, B, N; (1 <= N < 50)

第二行及以后: 一个最多200,000字符的序列,全是0或1; 每行字符数不大于80。

OUTPUT FORMAT:

(file contact.out)

输出N个频率最高的序列(按照频率由高到低的次序)。由短到长排列频率相同的这些序列,如果长短相同,按二进制大小排列。如果出现的序列个数小于N,输出存在的序列。

对于每个存在的频率,先输出单独包含该频率的一行,再输出以空格分隔的这些序列。每行六个(除非少于六个剩下)。


SAMPLE INPUT

2 4 10
01010010010001000111101100001010011001111000010010011110010000000

在样例里,序列100出现了12次,而序列1000出现了5次。次数最多的序列是00,出现了23次。


SAMPLE OUTPUT

23
00
15
01 10
12
100
11
11 000 001
10
010
8
0100
7
0010 1001
6
111 0000
5
011 110 1000
4
0001 0011 1100



【题解】这道题可一先用字典树保存所有可能的子串。然后取出每一种子串出现的次数,放到一个数组中排个序就可以了。


/*
ID:cymxyym1
TASK:contact
LANG:C++
*/
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;

struct flag{
	flag *next[2];
	int cont;
	char ss[15];
	flag(){
		next[0]=next[1]=0;
		memset(ss,0,sizeof(ss));
		cont=0;
	}
}*f[10000]; 
flag *root=new flag;

struct pp{
	int cont;
	char c[15];
	pp(){
		memset(c,0,sizeof(c)); 
	}
}w[10000];

char s[200100];
int A,B,N,len;
//建树; 
inline void add(int x,int y)
{
	flag *k=root;
	int i=0;
	while(i<y && x+i<=len){
		int t=s[x+i]-'0';
		if((k->next[t])==0)
		{
			k->next[t]=new flag;
			for(int e=0;e<=i;e++)k->next[t]->ss[e+1]=s[x+e];
		}
		k=k->next[t];
		if(i>=(A-1))k->cont++;
		i++;
	}
}
//排序要求 
bool pan(pp x,pp y){
	int i;
	for(i=14;i;i--){
		int a=0,b=0;
		if(x.c[i]=='0'|| x.c[i]=='1')a=1;
		if(y.c[i]=='0'|| y.c[i]=='1')b=1;
		if(!(a+b))continue;
		if((a+b)==1)return a==0?0:1;
		break;
	}
	for(int j=1;j<=i;j++)
		if(x.c[j]<y.c[j])return 0;
	 	else if(x.c[j]>y.c[j])return 1;
}

inline bool cmp(pp x,pp y){
	return x.cont==y.cont?pan(x,y):x.cont<y.cont;
}

int main()
{
	freopen("contact.in","r",stdin);
	freopen("contact.out","w",stdout);
	
	scanf("%d%d%d",&A,&B,&N);
	char ch;len=0;
	while(scanf("%c",&ch)!=EOF)
	if(ch=='0' || ch=='1')s[++len]=ch;
	for(int i=1;i<=len-A+1;i++)add(i,B);
	
	int p=0;f[1]=root;
	int head=1,tail=1;
	while(head<=tail){//宽搜所有子串; 
		flag *t=f[head++];
		w[++p].cont=t->cont;
		for(int e=1;e<=14;e++)w[p].c[e]=t->ss[e];
		
		if((t->next[0])!=0)
			f[++tail]=t->next[0];
		if((t->next[1])!=0)
			f[++tail]=t->next[1];
	}	
	sort(w+1,w+1+p,cmp);//排序;
	
	
	int time=0,i,chang;
	for(i=p;i;i--)if(w[i].cont!=0){
		if(w[i].cont!=w[i+1].cont || i==p){
			time++;
			if(time>N)break;
			if(i!=p)printf("\n");
			printf("%d\n",w[i].cont);
			int l=1;chang=0;
			while(w[i].c[l]=='0' || w[i].c[l]=='1')printf("%c",w[i].c[l++]);	
		}else{
			chang++;
			if(chang%6)printf(" ");
			else printf("\n");
			int l=1;
			while(w[i].c[l]=='0' || w[i].c[l]=='1')printf("%c",w[i].c[l++]);
		}
	} 
	printf("\n");
	return 0;
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值