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;}
原创粉丝点击