BSOI_2262.遥控车 (car.pas/c/cpp)
来源:互联网 发布:网络络建设总结 编辑:程序博客网 时间:2024/05/16 19:56
【问题描述】
平平带着韵韵来到了游乐园,看到了n辆漂亮的遥控车,每辆车上都有一个唯一的名字name[i]。韵韵早就迫不及待地想玩名字是s的遥控车。可是韵韵毕竟还小,她想象的名字可能是一辆车名字的前缀(也就是说能确定一个i,使s是name[i]的前缀),这时她就能玩第i辆车;或者是一个无中生有的名字,即s不是任何一辆车名字的前缀,这时候她什么也不能玩。
你需要完成下面的任务:
1.韵韵想了m个她想要的名字,请告诉她能玩多少次。
2.由于管理员粗心的操作,导致每辆车的摆放位置都可能出现微小的差错,原来第i辆车现在的位置可能是i-1、i、i+1中的任意一个(第1辆车的位置不可能是0,第n辆车的位置不可能是n+1)。请你计算出共有多少种可能的排列。
注:数据保证当s是name[i]的前缀时,i是唯一确定的。一辆车可以玩多次。
【文件输入】
第一行是2个正整数n、m。
接下来n行,每行1个字符串name[i],表示第i辆车的名字。接下来m行,每行1个字符串s,表示韵韵想要的名字。
【文件输出】
第一行输出韵韵能玩的次数。第二行输出共有多少种可能的排列。
【样例输入】
4 4
Abcd
DeF
AAa
aBccc
Ab
AA
AbC
aBcc
【样例输出】
3
5
【数据规模】
对于题目涉及到的字符串严格区分大小写,且长度小于255。
对于20%的数据 n≤10,m≤10;
对于40%的数据 n≤1000,m≤1000;
对于100%的数据 n≤10000,m≤10000。
【题目考点】
【思路点拨】
这道题设计两个基本独立的问题,一是字符串匹配问题,一个是找递推公式问题。
多次求字符串前缀匹配有以下几种优化方法:
1.对主串数组进行快排后,采用二分查找与匹配串比较。
2.采用字符树(trie树)进行主串记录,之后匹配
3.将主串数组与匹配串数组进行排序,之后进行线性扫描。[该方法只针对本题,因为题中说明了一个匹配串只能匹配一个主串]
方法2理论上很快,但实际效果可能比2、3慢,大多时候3很快,特快时匹配串很多时。一般采用方法1。
第二个问题是Fibonacci数列,f[i]=f[i-1]+f[i-2],f[1]=1;f[2]=2;多推几项就找到规律,这里要用高精度,采用滚动存储即可。
【方法一】:快排+二分查找+递推+高精度
#include<iostream>using namespace std;string s[10005],st,t;int b[10005],a[10005],n;void qsort(int L,int r){ int i=L,j=r;t=s[(L+r)/2]; while(i<=j) { while(s[i]<t)i++; while(s[j]>t)j--; if(i<=j)swap(s[i++],s[j--]); } if(i<r)qsort(i,r); if(L<j)qsort(L,j);}bool Find(){ int L=1,r=n,mid; while(L<=r) { mid=(L+r)/2; t=s[mid].substr(0,st.length()); if(st==t)return 1; if(st<t)r=mid-1;else L=mid+1; } return 0;}void print(int a[]){ if(a[0]==0)cout<<0;else for(int i=a[0];i>=1;i--)cout<<a[i]; cout<<endl;}void jia(int a[],int b[])//高精度加法{ int t[10005],i; t[0]=max(a[0],b[0]); for(i=1;i<=t[0];i++)t[i]=a[i]+b[i]; for(i=1;i<=t[0];i++)t[i+1]+=t[i]/10,t[i]%=10; if(t[t[0]+1]>0)t[0]++; for(i=0;i<=b[0];i++)a[i]=b[i]; for(i=0;i<=t[0];i++)b[i]=t[i];}int main(){ int m,i,j,ans=0; cin>>n>>m; for(i=1;i<=n;i++)cin>>s[i]; qsort(1,n); //把车得名字从小到大快排 for(i=1;i<=m;i++){cin>>st;if(Find())ans++;}//二分查找 cout<<ans<<endl; a[0]=1;a[1]=1;b[0]=1;b[1]=2; for(i=3;i<=n;i++)jia(a,b); print(b); return 0;}
【方法2】双指针+递推+高精度
【方法3】trie树+递推+高精度
#include<fstream>using namespace std;ifstream cin("car.in");ofstream cout("car.out");struct Tire{ int ch[60]; bool end; //结束标记 void init(){end=0;memset(ch,0,sizeof(ch));}//trie树初始化}tree[10005*70];string s[10005],st;int b[10005],a[10005],n,t[10005],cnt=0;void Insert(string s) //trie树的插入{ int i=0,x=0,y; //根为x=0 while(i<s.length()) { y=s[i]-'A'; if(tree[x].ch[y]==0) //原来没有节点,新增加节点 { tree[x].ch[y]=++cnt; //记录此节点的编号 tree[cnt].init();//初始化 x=cnt; } else x=tree[x].ch[y]; //有节点,沿着路径往下走 i++; } tree[x].end=1;}int Find(string s) //查找s是否在trie树中{ int y,i=0,x=0; //根为x=0 while(i<s.length()) { y=s[i]-'A'; if(tree[x].ch[y]==0)return 0;//表示没有在 x=tree[x].ch[y]; i++; } return 1; //返回查找成功}void print(int a[]){ if(a[0]==0)cout<<0; else for(int i=a[0];i>=1;i--)cout<<a[i]; cout<<endl;}void jia(int a[],int b[])//高精度加法 { int i; memset(t,sizeof(t),0); t[0]=max(a[0],b[0]); for(i=1;i<=t[0];i++)t[i]=a[i]+b[i]; for(i=1;i<=t[0];i++){t[i+1]+=t[i]/10;t[i]%=10;} if(t[t[0]+1]>0)t[0]++; for(i=0;i<=b[0];i++)a[i]=b[i]; for(i=0;i<=t[0];i++)b[i]=t[i];}int main(){ int m,i,j,ans=0; cin>>n>>m; for(i=1;i<=n;i++){cin>>s[i];Insert(s[i]);} for(i=1;i<=m;i++){cin>>st;if(Find(st))ans++;} cout<<ans<<endl; a[0]=1;a[1]=1;b[0]=1;b[1]=2; for(i=3;i<=n;i++)jia(a,b); print(b); return 0;}
我的做法: 二分查找+递推高精度
#include<cstdio>#include<algorithm>#include<cstring>#define L 10001#define N 5001#define M 256#define P 1000000using namespace std;struct name{ char s[M]; bool operator<(const name &a)const { return strcmp(s,a.s)<0; }}a[L];void plus(int b[],int c[],int d[]){ for(int i=N;i>=1;i--) { d[i]+=b[i]+c[i]; d[i-1]=d[i]/P; d[i]%=P; }}void print(int c[]){ int i=1; while(!c[i]) i++; printf("%d",c[i++]); for(int j=i;j<=N;j++) printf("%06d",c[j]);}int n,m,ans=0;int main(){ freopen("car.in","r",stdin); freopen("car.out","w",stdout); scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%s",a[i].s); sort(a+1,a+1+n); for(int i=1;i<=m;i++) { char s[M]=""; scanf("%s",s); int l=1,r=n; while(l<=r) { int mid=(l+r)/2; char t[M]=""; strncpy(t,a[mid].s,strlen(s)); if(strcmp(s,t)>0) l=mid+1; else if(strcmp(s,t)<0) r=mid-1; else { ans++; break; } } } printf("%d\n",ans); int b[N+1],c[N+1],d[N+1]; memset(b,0,sizeof(b)); memset(c,0,sizeof(c)); b[N]=1,c[N]=2; for(int i=3;i<=n;i++) { memset(d,0,sizeof(d)); plus(b,c,d); memcpy(b,c,sizeof(c)); memcpy(c,d,sizeof(d)); } print(d); fclose(stdin); fclose(stdout); return 0;}
- BSOI_2262.遥控车 (car.pas/c/cpp)
- mm.cpp/c/pas
- set.cpp/c/pas
- 火星人(martian.pas/c/cpp)
- 飙车[nfs.pas/c/cpp]
- 船(ships.pas/c/cpp)
- 采药(medic.pas/c/cpp)
- 报数( Read . pas / c / cpp )
- 机器分配(machine.c/cpp/pas)
- 硬币找零(coin.c/cpp/pas)
- 编辑距离(edit.c/cpp/pas)
- 传球游戏(ball.pas/c/cpp)
- 逃亡的准备(hallows.pas/c/cpp)
- 整数划分(文件名:separate.c/cpp/pas)
- 配置魔药(medic.pas/c/cpp)
- 青蛙的烦恼 (frog.pas/c/cpp)
- 淘汰赛制(elimination.pas/c/cpp)
- 宝物筛选(Treasure.pas/c/cpp)
- Rocket简介(1)
- Java的数据类型
- BZOJ 4720 [Noip2016]换教室——期望DP
- wamp多版本php的配置
- Factorial vs Power
- BSOI_2262.遥控车 (car.pas/c/cpp)
- JVM内存模型(深入理解Java虚拟机学习笔记)
- hibernate框架一之基本知识及编写一个基本的项目
- codeforces 808D
- @Autowired与@Resource的区别
- java开发命名规范总结
- Python的RSA
- 学习curses图形库(四)
- linux后台运行和关闭、查看后台任务