A:
题目:
帽子 | ||||||
|
||||||
Description | ||||||
由字典里其他两个单词组成的单词为帽子单词,你要找到字典里所有的帽子单词。 | ||||||
Input | ||||||
只有一组输入数据 输入包含若干个小写单词,每行一个单词并且按照字典序排序。最多不超过50000个单词。每个单词长度不超过15. |
||||||
Output | ||||||
你需要按照字典序输出字典中的所有帽子单词。 | ||||||
Sample Input | ||||||
cat catdog dog |
||||||
Sample Output | ||||||
catdog | ||||||
Source | ||||||
HCPC2014校赛训练赛 3 | ||||||
Author | ||||||
曹振海 |
这个题可以用map水过,省时的方法还是字典树
map代码:
1 #include<iostream> 2 #include<string.h> 3 #include<stdio.h> 4 #include<map> 5 using namespace std; 6 7 map<string,int>mp; 8 9 int main() 10 { 11 int k=0; 12 string str[50005]; 13 //freopen("aa.txt","r",stdin); 14 while(cin>>str[k]) 15 { 16 mp[str[k]]=1; 17 k++; 18 } 19 for(int i=0;i<k;i++) 20 { 21 int len=str[i].length(); 22 for(int j=1;j<len;j++) 23 { 24 string s1=str[i].substr(0,j); 25 string s2=str[i].substr(j,len); 26 if(mp[s1]==1&&mp[s2]==1){ 27 cout<<str[i]<<endl; 28 break; 29 } 30 } 31 } 32 return 0; 33 }
字典树数组模拟带代码:
1 #include<iostream> 2 #include<string.h> 3 #include<stdio.h> 4 using namespace std; 5 6 const int maxn=1000005; 7 8 int tire[maxn][26]; 9 int flag[maxn]; 10 int tot; 11 12 void Insert(char *s,int rt) 13 { 14 int len=strlen(s); 15 for(int i=0;i<len;i++) 16 { 17 int x=s[i]-'a'; 18 if(tire[rt][x]==0) 19 tire[rt][x]=tot++; 20 rt=tire[rt][x]; 21 } 22 flag[rt]=1; 23 } 24 25 bool Find2(char *s,int rt,int i) 26 { 27 int len=strlen(s); 28 for(int j=i;j<len;j++) 29 { 30 int x=s[j]-'a'; 31 if(tire[rt][x]==0) 32 return false; 33 rt=tire[rt][x]; 34 } 35 return flag[rt]; 36 } 37 38 bool Find(char *s,int rt) 39 { 40 41 int len=strlen(s); 42 for(int i=0;i<len;i++) 43 { 44 int x=s[i]-'a'; 45 if(tire[rt][x]==0) 46 return false; 47 if(flag[rt]&&Find2(s,0,i)) 48 return true; 49 rt=tire[rt][x]; 50 } 51 return false; 52 } 53 54 int main() 55 { 56 int k=0; 57 tot=1; 58 char str[50005][20]; 59 //freopen("aa.txt","r",stdin); 60 while(scanf("%s",str[k])!=EOF) 61 { 62 Insert(str[k],0); 63 k++; 64 } 65 for(int i=0;i<k;i++) 66 { 67 if(Find(str[i],0)) 68 printf("%s ",str[i]); 69 } 70 return 0; 71 }
字典树指针代码:
1 #include<iostream> 2 #include<string.h> 3 #include<stdio.h> 4 using namespace std; 5 6 struct tire 7 { 8 tire *next[26]; 9 bool flag; 10 tire() 11 { 12 for(int i=0;i<26;i++) 13 { 14 next[i]=NULL; 15 flag=false; 16 } 17 } 18 }root; 19 20 void Insert(char *s) 21 { 22 tire *rt=&root; 23 for(int i=0;s[i];i++) 24 { 25 int x=s[i]-'a'; 26 if(rt->next[x]==NULL) 27 { 28 rt->next[x]=new tire; 29 } 30 rt=rt->next[x]; 31 } 32 rt->flag=true; 33 } 34 35 bool Find2(char *s,int i) 36 { 37 tire *rt=&root; 38 for(int j=i;s[j];j++) 39 { 40 int x=s[j]-'a'; 41 if(rt->next[x]==NULL) 42 return false; 43 44 rt=rt->next[x]; 45 } 46 return rt->flag; 47 } 48 49 bool Find(char *s) 50 { 51 tire *rt=&root; 52 for(int i=0;s[i];i++) 53 { 54 int x=s[i]-'a'; 55 if(rt->next[x]==NULL) 56 return false; 57 58 if(rt->flag&&Find2(s,i)) 59 return true; 60 61 rt=rt->next[x]; 62 } 63 return false; 64 } 65 66 int main() 67 { 68 int k=0; 69 char str[50005][20]; 70 //freopen("aa.txt","r",stdin); 71 while(scanf("%s",str[k])!=EOF) 72 { 73 Insert(str[k]); 74 k++; 75 } 76 for(int i=0;i<k;i++) 77 { 78 if(Find(str[i])) 79 printf("%s ",str[i]); 80 } 81 return 0; 82 }
B:
背单词 | ||||||
|
||||||
Description | ||||||
大四了,Leyni感觉好惆怅,因为找不到工作,所以最后决定考研了,可是Leyni的英语好差,没办法,先从最基本的背单词开始吧。那么多单词怎么才好背呢,话说考研界盛传利用前缀背单词,貌似好神奇的样子。因为英语单词很多,Leyni想要知道以一个特定字符串做前缀的单词有多少,于是他来找你帮忙了。 |
||||||
Input | ||||||
输入首先包含若干行小写单词,表示字典里的单词,以END结束,然后是若干个询问字符串,表示单词的前缀。输入到文件结束。最多不超过50000个单词。每个单词长度不超过15。 | ||||||
Output | ||||||
对于每一个询问字符串,每行输出一个整数,表示单词表里有多少单词以此字符串作为前缀。 | ||||||
Sample Input | ||||||
a ab aba abcaa END aba a ab abcd |
||||||
Sample Output | ||||||
1 4 3 0 |
||||||
Source | ||||||
HCPC2014校赛训练赛 3 | ||||||
Author | ||||||
曹振海 |
这个题同样可以用字典树和map做:
map代码:
1 #include<iostream> 2 #include<string.h> 3 #include<stdio.h> 4 #include<map> 5 using namespace std; 6 7 map<string,int>mp; 8 9 int main() 10 { 11 string s; 12 //freopen("aa.txt","r",stdin); 13 while(cin>>s) 14 { 15 if(s=="END") 16 break; 17 int len=s.length(); 18 for(int i=0;i<=len;i++) 19 { 20 string s1=s.substr(0,i); 21 mp[s1]++; 22 } 23 } 24 while(cin>>s) 25 { 26 if(s=="END") 27 break; 28 cout<<mp[s]<<endl; 29 } 30 return 0; 31 }
字典树数组模拟:
1 #include<iostream> 2 #include<string.h> 3 #include<stdio.h> 4 #include<map> 5 using namespace std; 6 7 const int maxn=1000005; 8 9 int tire[maxn][26]; 10 int num[maxn]; 11 int tot; 12 13 void Insert(char *s,int rt) 14 { 15 int len=strlen(s); 16 for(int i=0;i<len;i++) 17 { 18 int x=s[i]-'a'; 19 if(tire[rt][x]==0) 20 tire[rt][x]=tot++; 21 rt=tire[rt][x]; 22 num[rt]++; 23 } 24 } 25 26 int Find(char *s,int rt) 27 { 28 int len=strlen(s); 29 for(int j=0;j<len;j++) 30 { 31 int x=s[j]-'a'; 32 if(tire[rt][x]==0) 33 return 0; 34 rt=tire[rt][x]; 35 } 36 return num[rt]; 37 } 38 39 int main() 40 { 41 char s[maxn]; 42 tot=1; 43 //freopen("aa.txt","r",stdin); 44 while(scanf("%s",s)) 45 { 46 if(strcmp(s,"END")==0) 47 break; 48 Insert(s,0); 49 } 50 while(scanf("%s",s)!=EOF) 51 { 52 printf("%d ",Find(s,0)); 53 } 54 return 0; 55 }
字典树指针:
1 #include<iostream> 2 #include<string.h> 3 #include<stdio.h> 4 using namespace std; 5 6 const int maxn=10005; 7 8 struct tire 9 { 10 tire *next[26]; 11 int num; 12 tire() 13 { 14 for(int i=0;i<26;i++) 15 { 16 next[i]=NULL; 17 num=0; 18 } 19 } 20 }root; 21 22 void Insert(char *s) 23 { 24 tire *rt=&root; 25 for(int i=0;s[i];i++) 26 { 27 int x=s[i]-'a'; 28 if(rt->next[x]==NULL) 29 { 30 rt->next[x]=new tire; 31 } 32 rt=rt->next[x]; 33 rt->num++; 34 } 35 } 36 37 int Find(char *s) 38 { 39 tire *rt=&root; 40 for(int j=0;s[j];j++) 41 { 42 int x=s[j]-'a'; 43 if(rt->next[x]==NULL) 44 return 0; 45 rt=rt->next[x]; 46 } 47 return rt->num; 48 } 49 50 int main() 51 { 52 char s[maxn]; 53 //freopen("aa.txt","r",stdin); 54 while(scanf("%s",s)) 55 { 56 if(strcmp(s,"END")==0) 57 break; 58 Insert(s); 59 } 60 while(scanf("%s",s)!=EOF) 61 { 62 printf("%d ",Find(s)); 63 } 64 return 0; 65 }
C:
搬果子 | ||||||
|
||||||
Description | ||||||
果园里面有n堆果子,每堆果子有xi个,每个果子的重量为1,小明每次把i,j两堆果子移成一堆,需要花费的体力为xi+xj。最后移成一堆,求最小花费体力值。 其中1<=n<=10000,1<=m<=10000。均为正整数。 |
||||||
Input | ||||||
每组数据第一行输入一个正整数n,表示有n堆果子。 接下来一行有n个正整数,表示每堆果子的重量。 输入以EOF结尾。 |
||||||
Output | ||||||
每组数据单独一行,输出所花费的最小体力值。 |
||||||
Sample Input | ||||||
3 1 2 9 5 1 3 9 18 30 |
||||||
Sample Output | ||||||
15 109 |
||||||
Hint | ||||||
Source | ||||||
HCPC2014校赛训练赛 3 | ||||||
Author | ||||||
BH |
这个题可以用堆或者优先队列来写
优先队列模板:额……慢的要死
1 #include<iostream> 2 #include<stdio.h> 3 #include<string.h> 4 #include<queue> 5 using namespace std; 6 7 int main() 8 { 9 int n,num,ans; 10 //freopen("aa.txt","r",stdin); 11 while(scanf("%d",&n)!=EOF) 12 { 13 ans=0; 14 priority_queue<int,vector<int>,greater<int> >q; 15 while(n--) 16 { 17 scanf("%d",&num); 18 q.push(num); 19 } 20 while(q.size()>1) 21 { 22 int a1=q.top(); 23 q.pop(); 24 int a2=q.top(); 25 q.pop(); 26 ans+=(a1+a2); 27 q.push(a1+a2); 28 } 29 printf("%d ",ans); 30 } 31 return 0; 32 }
堆(有点懒了,直接用的stl==)
1 #include<iostream> 2 #include<string.h> 3 #include<algorithm> 4 #include<stdio.h> 5 #include<vector> 6 using namespace std; 7 8 const int maxn=10005; 9 int a[maxn]; 10 11 bool cmp(int x,int y) 12 { 13 return x>y; 14 } 15 16 int main() 17 { 18 int n; 19 //freopen("aa.txt","r",stdin); 20 while(scanf("%d",&n)!=EOF) 21 { 22 int ans=0; 23 for(int i=0;i<n;i++) 24 scanf("%d",&a[i]); 25 make_heap(a,a+n,cmp); 26 while(n>1){ 27 pop_heap(a,a+n,cmp); 28 pop_heap(a,a+n-1,cmp); 29 a[n-2]+=a[n-1]; 30 ans+=a[n-2]; 31 n--; 32 push_heap(a,a+n,cmp); 33 } 34 printf("%d ",ans); 35 } 36 return 0; 37 }
D:
截取方案数 | ||||||
|
||||||
Description | ||||||
给定一个模式串T,主串S,问:从S中截取T有多少种方案? |
||||||
Input | ||||||
有多组测试数据,对于每组测试数据,第一行是模式串T,第二行是主串S,数据中仅包含大小写字母和数字,模式串T长度不超过10^4, 主串S长度不超过10^5。 注意:数据是随机的。 |
||||||
Output | ||||||
对于每组测试数据,输出一行,为截取方案数。 |
||||||
Sample Input | ||||||
abc abcdaabcab abcd abcdaabcab aba abababa |
||||||
Sample Output | ||||||
2 1 3 |
kmp模板题:
代码:
1 #include<iostream> 2 #include<string.h> 3 #include<algorithm> 4 #include<stdio.h> 5 #include<vector> 6 using namespace std; 7 8 const int maxn=100005; 9 char s1[maxn],s2[maxn]; 10 int next[maxn]; 11 int len1,len2; 12 13 void get_next() 14 { 15 int i,j; 16 next[1]=0; 17 for (i=0,j=2;j<=len2;j++) 18 { 19 while(i>0&&s2[i+1]!=s2[j]) 20 i=next[i]; 21 if(s2[i+1]==s2[j]) 22 i++; 23 next[j]=i; 24 } 25 } 26 27 int kmp() 28 { 29 int i,j,res=0; 30 for(i=1,j=0;i<=len2;i++) 31 { 32 while(j>0&&s1[j+1]!=s2[i]) 33 j=next[j]; 34 if(s1[j+1]==s2[i]) 35 j++; 36 if(j==len1) 37 { 38 res++; 39 j=next[j]; 40 } 41 } 42 return res; 43 } 44 45 int main() 46 { 47 //freopen("aa.txt","r",stdin); 48 while(gets(s1+1)) 49 { 50 gets(s2+1); 51 len1=strlen(s1+1); 52 len2=strlen(s2+1); 53 get_next(); 54 printf("%d ",kmp()); 55 } 56 return 0; 57 }
E:
消息队列 | ||||||
|
||||||
Description | ||||||
Windows操作系统是基于消息的,也就是说任何的事件,包括鼠标移动和点击,键盘的输入,都会被放入操作系统的消息队列中,而消息本身带有一定的参数和优先级。Windows会优先处理优先级较高的消息,当两个消息优先级相同时,按照先来先服务的原则进行处理,你的任务就是模拟这种机制。 | ||||||
Input | ||||||
输入首先分为两种,GET表示从消息队列中取出一个消息。PUT表示把一个消息放入消息队列,每一个消息包含三个部分:内容,参数和优先级(数字越小优先级越高)。输入亦按照此顺序进行。消息的内容长度不会超过15。最多不超过60000个操作。 | ||||||
Output | ||||||
对于每一个GET操作,若队列为空,输出EMPTY QUEUE!否则输出按照规则得到的第一个消息的内容和参数。 | ||||||
Sample Input | ||||||
GET PUT msgone 11 6 PUT msgtwo 8 4 GET GET GET |
||||||
Sample Output | ||||||
EMPTY QUEUE! msgtwo 8 msgone 11 EMPTY QUEUE! |
||||||
Source | ||||||
HCPC2014校赛训练赛 3 | ||||||
Author | ||||||
曹振海 |
基于优先队列的基本操作
代码:
1 #include<stdio.h> 2 #include<string.h> 3 #include<iostream> 4 #include<algorithm> 5 #include<cmath> 6 #include<queue> 7 using namespace std; 8 struct que{ 9 char str[20]; 10 int youxian,canshu,shijian; 11 }; 12 struct cmp{ 13 bool operator()(const que &a,const que &b) { 14 if(a.youxian!=b.youxian) 15 return a.youxian>b.youxian; 16 return a.shijian>b.shijian; 17 } 18 }; 19 int main() 20 { 21 priority_queue< que, vector<que>, cmp > p; 22 char s[20],a[20]; 23 que aa; 24 int c,y,o=0; 25 while(~scanf("%s",&s)){o++; 26 if(s[0]=='P'){ 27 scanf("%s",&aa.str); 28 scanf("%d%d",&aa.canshu,&aa.youxian); 29 aa.shijian=o; 30 p.push(aa); 31 }else{ 32 if(p.empty()) 33 printf("EMPTY QUEUE! "); 34 else{ 35 aa=p.top(); 36 printf("%s %d ",aa.str,aa.canshu); 37 p.pop(); 38 } 39 } 40 } 41 return 0; 42 }
F;
最小的n个和 | ||||||
|
||||||
Description | ||||||
给定A、B两个数列,各包含n个数,分别从A和B中任意取一个数相加得到和,这样会有n^2种结果(包括重复的),求n^2个结果中前n个最小的和。 |
||||||
Input | ||||||
有多组测试数据。 对于每组测试数据,第一行为n,第二行为数列A,第三行为数列B。 1<=n<=100000, 0 <= Ai, Bi <= 10^9。 |
||||||
Output | ||||||
对于每组测试数据,输出一行,包含前n个最小的和,按照升序输出,两数之间用一个空格隔开。 |
||||||
Sample Input | ||||||
5 1 3 4 2 0 7 3 5 2 11 10 74 50 47 45 38 64 19 2 84 69 91 46 44 7 67 1 40 60 78 41 |
||||||
Sample Output | ||||||
2 3 3 4 4 3 9 20 26 39 42 43 45 46 46 |
||||||
Source | ||||||
HCPC2014校赛训练赛 3 |
比赛的时候没做出来,现在做出来了:
代码:
1 #include<iostream> 2 #include<string.h> 3 #include<algorithm> 4 #include<stdio.h> 5 using namespace std; 6 7 const int maxn=100005; 8 int a[maxn],b[maxn],c[maxn]; 9 10 int main() 11 { 12 int n; 13 //freopen("aa.txt","r",stdin); 14 while(scanf("%d",&n)!=EOF) 15 { 16 for(int i=0;i<n;i++) 17 scanf("%d",&a[i]); 18 for(int i=0;i<n;i++) 19 scanf("%d",&b[i]); 20 sort(a,a+n); 21 sort(b,b+n); 22 for(int i=0;i<n;i++) 23 c[i]=a[0]+b[i]; 24 make_heap(c,c+n); 25 for(int i=1;i<n;i++) 26 { 27 for(int j=0;j<n;j++) 28 { 29 int x=a[i]+b[j]; 30 if(x<c[0]) 31 { 32 pop_heap(c,c+n); 33 c[n-1]=x; 34 push_heap(c,c+n); 35 } 36 else 37 break; 38 } 39 } 40 sort_heap(c,c+n); 41 for(int i=0;i<n;i++) 42 printf(i==0?"%d":" %d",c[i]); 43 printf(" "); 44 } 45 return 0; 46 }