bupt2014暑假新生归来赛(1)

      今天,是暑假集训正式开始的一天,有一场新生归来赛。由于今天明天有些事情,所以就今晚就只能写今天A掉的那俩水题了。。明晚再去研究剩下的三道题。。

好了,废话少说,开始我的第一个博客,这次训练的题解。

      首先,A题,水题一道。直接略过,没有什么写题解的必要,不如去看其他的NIM博弈的题。

     再就是今天的重点,虽然也是一道水题,不过也还有写一些的必要。

    先放题目,

时间限制 1000 ms   内存限制 65536 KB

题目描述

给定一个由小写字母a到z组成的字符串S,其中第i个字符为S[i](下标从0开始)。你需要完成下面两个操作: INSERT c 其中c是一个待输入的字符。你需要在字符串的末尾添加这个字符。保证输入的字符同样是a到z之间的一个小写字母。 QUERY x 其中x是一个输入的整数下标。对于这个询问,你需要回答在S当中和S[x]相等且与x最近的距离。输入保证x在当前字符串中合法。 例如S = "abcaba",如果我们操作: INSERT a 则在S的末端加一个字符a,S变成"abcabaa"。 接下来操作 QUERY 0 由于S[0] = a,在S中出现的离他最近的a在下标为3的位置上,距离为3 - 0 = 3。因此应当输出3。 接下来,如果 QUERY 4 S[4] = b,S中离它最近的b出现在下标为1处,距离为4 - 1 = 3。同样应当输出3。 给定初始字符串S和若干操作,对于每个QUERY,你需要求出相应的距离。

输入格式

输入的第一行是一个正整数 T T(T<=20),表示测试数据的组数。 每组输入数据的第一行是一个初始串S。第二行是一个正整数m( 1<=m<=100000 ),表示总共操作的数量。接下来m行,每行表示一个操作。操作的格式如上所述。 数据保证在任何情况下,S的长度不会超过100000。 OutputFormat 对于每个QUERY,输出所求的最小距离。如果S中其它位置都不存在和它相同的字符,输出-1。

输出格式

对于每个QUERY,输出所求的最小距离。如果S中其它位置都不存在和它相同的字符,输出-1。

输入样例

2
axb
3
INSERT a
QUERY 0
QUERY 1
explore
3
INSERT r
QUERY 7
QUERY 1

输出样例

3
-1
2
-1

 

 

 

    我用了一个动态数组来存储相同字母出现的位置,然后每添加一次就维护一次,查询时用二分进行查找。

    咱分析题目中出现的字符串,首先,第一次输入的字符串,拿样例来举例的吧,比如,axb,从头到尾,每出现一个字母,就把他存到对应的数组中,比如这个单词,就有

a['a'-'a'][0]=0,a['x'-'a'][0]=1,a['b'-'a'][0]=2;然后就有添加一个a,由于原来已经存在一个a了,所以这次应该是a['a'-'a'][1]=3,着用动态数组很容易实现 ; 其他的例子也是如此。

    那么,查找该怎么办呢?很容易看出来,存入数组之后,数组所记录的数据时有序的,有序就简单了,二分法,只有logn的复杂度,肯定不会超时。(弱渣写个二分还出了好多问题)

   下面贴代码

 

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <vector>
 
using namespace std;
 
#define N 100005
 
char s[N]={0};
vector< int > a[30];//动态数组存储位置,下标代表字母。
 
void init()
{
     memset (s,0, sizeof (s));
     for ( int i=0;i<=26;i++)
         a[i].clear();
}
 
int divideSearch( int ch, int n)//二分查找
{
     int l=0,r=a[ch].size()-1;
     int mid=(l+r)/2;
     if (a[ch].size()==1)  return -1;
     if (a[ch][l]==n) mid=l;
     if (a[ch][r]==n) mid=r;
     while (a[ch][mid]!=n)
     {
         if (a[ch][mid]>n) r=mid;
         if (a[ch][mid]<n) l=mid;
         mid=(l+r)/2;
         if (a[ch][l]==n) mid=l;
         if (a[ch][r]==n) mid=r;
     }
     if (mid==0)  return a[ch][1]-a[ch][0];
     else if (mid==a[ch].size()-1)  return a[ch][a[ch].size()-1]-a[ch][a[ch].size()-2];
     return min(a[ch][mid+1]-a[ch][mid],a[ch][mid]-a[ch][mid-1]);
}
 
int main()
{
     int t;
     cin>>t;
     while (t--)
     {
         init();
         int m;
         scanf ( "%s" ,s);
         int length= strlen (s);
         for ( int i=0;i<length;i++)
         {
             a[s[i]- 'a' ].push_back(i);
         }
         scanf ( "%d" ,&m);
         for ( int i=1;i<=m;i++)
         {
             char order[10];
             scanf ( "%s" ,order);
             if ( strcmp (order, "INSERT" )==0)
             {
                 char ch;
                 scanf ( "%s" ,&ch);
                 a[ch- 'a' ].push_back(length);
                 s[length]=ch;
                 length++;
                 s[length]= '\0' ;
             }
             else if ( strcmp (order, "QUERY" )==0)
             {
                 int n;
                 scanf ( "%d" ,&n);
                 int ans=divideSearch(s[n]- 'a' ,n);
                 printf ( "%d\n" ,ans);
             }
         }
     }
 
}

 

    今天就到这里,等后天研究完剩下的题目,依然会继续发题解的。

   

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值