2016百度之星资格赛

题目:Problem A

链接:http://acm.hdu.edu.cn/showproblem.php?pid=5685

Problem A

   
 Accepts: 1662
   
 Submissions: 11595
 Time Limit: 2000/1000 MS (Java/Others)
   
 Memory Limit: 65536/65536 K (Java/Others)
Problem Description

度熊手上有一本字典存储了大量的单词,有一次,他把所有单词组成了一个很长很长的字符串。现在麻烦来了,他忘记了原来的字符串都是什么,神奇的是他竟然记得原来那些字符串的哈希值。一个字符串的哈希值,由以下公式计算得到:

H(s)=∏i=1i≤len(s)(Si−28) (mod 9973)H(s)=\prod_{i=1}^{i\leq len(s)}(S_{i}-28)\ (mod\ 9973)H(s)=i=1ilen(s)(Si28) (mod 9973)

SiS_{i}Si代表 S[i] 字符的 ASCII 码。

请帮助度熊计算大字符串中任意一段的哈希值是多少。

Input

多组测试数据,每组测试数据第一行是一个正整数NNN,代表询问的次数,第二行一个字符串,代表题目中的大字符串,接下来NNN行,每行包含两个正整数aaabbb,代表询问的起始位置以及终止位置。

1≤N≤1,0001\leq N\leq 1,0001N1,000

1≤len(string)≤100,0001\leq len(string)\leq 100,0001len(string)100,000

1≤a,b≤len(string)1\leq a,b\leq len(string)1a,blen(string)

Output

对于每一个询问,输出一个整数值,代表大字符串从 aaa 位到 bbb 位的子串的哈希值。

Sample Input
2
ACMlove2015
1 11
8 10
1
testMessage
1 1
Sample Output
6891
9240
88

题意:对于一个字符串,定义一个哈希值 ∏是连乘,给一个字符串s,现有n个操作,每次操作询问下标 l 到 r 之间的子串的哈希值,前缀的思想,先预处理出0到每一位的哈希值gi,现在只涉及到g[r]和g[l-1],不过因为涉及到取模操作,所以不能直接除,应该找g[l-1]的逆元e,答案便是g[r]*e%9973。



#include<bits/stdc++.h>
using namespace  std;
typedef  long long ll;
const int mod=9973;
const int N = 1e5 + 5;
int inv[mod+5];
int ha[N];
char s[N];

void inverse(int n, int p) {
    inv[1] = 1;
    for (int i=2; i<=n; ++i) {
        inv[i] = (ll) (p - p / i) * inv[p%i] % p;
    }
}

void  init_hash(int n){
  ha[0]=1;
  for(int i=1; i<=n; i++){
    ha[i]=(ll) ha[i-1]*(s[i]-28) %mod;
  }
}

int main(){
  inverse(mod,mod);
  int t;
  while(~scanf("%d",&t)){
    scanf("%s",s+1);
    int  n=strlen(s+1);
    init_hash(n);
    int l,r;
    while(t--){
      scanf("%d %d",&l,&r);
      printf("%d\n",(ll)ha[r]*inv[ha[l-1]]%mod);
    }
  }
  return 0;
}

题目:Problem B

链接:http://acm.hdu.edu.cn/showproblem.php?pid=5686

Problem B

   
 Accepts: 2258
   
 Submissions: 8344
 Time Limit: 2000/1000 MS (Java/Others)
   
 Memory Limit: 65536/65536 K (Java/Others)
Problem Description

度熊面前有一个全是由1构成的字符串,被称为全1序列。你可以合并任意相邻的两个1,从而形成一个新的序列。对于给定的一个全1序列,请计算根据以上方法,可以构成多少种不同的序列。

Input

这里包括多组测试数据,每组测试数据包含一个正整数NNN,代表全1序列的长度。

1≤N≤2001\leq N \leq 2001N200

Output

对于每组测试数据,输出一个整数,代表由题目中所给定的全1序列所能形成的新序列的数量。

Sample Input
1
3
5
Sample Output
1
3
8


       
       
Hint
如果序列是:(111)。可以构造出如下三个新序列:(111), (21), (12)。

题意:有一个只含有1的字符串,现在可以将任意相邻的1变为2,问可以形成多少种不同的字符串。比如111可以变为12,21,111。给你一个n表示1的数量,输出不同字符串的数量。

思路:dp的水题,斐波拉契数列,大数。可以想象11111...可以分成(2)111...与1(1111)...,现在有两种情况:

  第一个1动:前两个1变为2,后面的111...再变,这种情况的数量是dp[n-2];

  第一个1不动:这种情况的数量是dp[n-1];

注意:n很大,需要大数处理,只需要加法,而且时间限制也不是很紧,随便过(直接套整个高精度模板了,也没删改)。

#include <bits/stdc++.h>
using namespace std;

#define MAXN 9999
#define MAXSIZE 10
#define DLEN 4
class BigNum
{
private:
    int a[1500];    //可以控制大数的位数
    int len;       //大数长度
public:
    BigNum() { len = 1; memset(a, 0, sizeof(a)); }   //构造函数
    BigNum(const int);       //将一个int类型的变量转化为大数
    BigNum(const char*);     //将一个字符串类型的变量转化为大数
    BigNum(const BigNum &);  //拷贝构造函数
    BigNum &operator=(const BigNum &);   //重载赋值运算符,大数之间进行赋值运算
    friend istream& operator>>(istream&, BigNum&);   //重载输入运算符
    friend ostream& operator<<(ostream&, BigNum&);   //重载输出运算符
    BigNum operator+(const BigNum &) const;   //重载加法运算符,两个大数之间的相加运算
    BigNum operator-(const BigNum &) const;   //重载减法运算符,两个大数之间的相减运算
    BigNum operator*(const BigNum &) const;   //重载乘法运算符,两个大数之间的相乘运算
    BigNum operator/(const int   &) const;    //重载除法运算符,大数对一个整数进行相除运算
    BigNum operator^(const int  &) const;    //大数的n次方运算
    int    operator%(const int  &) const;    //大数对一个int类型的变量进行取模运算
    bool   operator>(const BigNum & T)const;   //大数和另一个大数的大小比较
    bool   operator>(const int & t)const;      //大数和一个int类型的变量的大小比较
    void print();       //输出大数
    void printline();    //输出大数并换行
};
BigNum::BigNum(const int b)     //将一个int类型的变量转化为大数
{
    int c, d = b;
    len = 0;
    memset(a, 0, sizeof(a));
    while (d > MAXN)
    {
        c = d - (d / (MAXN + 1)) * (MAXN + 1);
        d = d / (MAXN + 1);
        a[len++] = c;
    }
    a[len++] = d;
}
BigNum::BigNum(const char*s)     //将一个字符串类型的变量转化为大数
{
    int t, k, index, l, i;
    memset(a, 0, sizeof(a));
    l = strlen(s);
    len = l / DLEN;
    if (l%DLEN)
        len++;
    index = 0;
    for (i = l - 1; i >= 0; i -= DLEN)
    {
        t = 0;
        k = i - DLEN + 1;
        if (k<0)
            k = 0;
        for (int j = k; j <= i; j++)
            t = t * 10 + s[j] - '0';
        a[index++] = t;
    }
}
BigNum::BigNum(const BigNum & T) : len(T.len)  //拷贝构造函数
{
    int i;
    memset(a, 0, sizeof(a));
    for (i = 0; i < len; i++)
        a[i] = T.a[i];
}
BigNum & BigNum::operator=(const BigNum & n)   //重载赋值运算符,大数之间进行赋值运算
{
    int i;
    len = n.len;
    memset(a, 0, sizeof(a));
    for (i = 0; i < len; i++)
        a[i] = n.a[i];
    return *this;
}
istream& operator>>(istream & in, BigNum & b)   //重载输入运算符
{
    char ch[MAXSIZE * 4];
    int i = -1;
    in >> ch;
    int l = strlen(ch);
    int count = 0, sum = 0;
    for (i = l - 1; i >= 0;)
    {
        sum = 0;
        int t = 1;
        for (int j = 0; j<4 && i >= 0; j++, i--, t *= 10)
        {
            sum += (ch[i] - '0')*t;
        }
        b.a[count] = sum;
        count++;
    }
    b.len = count++;
    return in;
}
ostream& operator<<(ostream& out, BigNum& b)   //重载输出运算符
{
    int i;
    cout << b.a[b.len - 1];
    for (i = b.len - 2; i >= 0; i--)
    {
        cout.width(DLEN);
        cout.fill('0');
        cout << b.a[i];
    }
    return out;
}
BigNum BigNum::operator+(const BigNum & T) const   //两个大数之间的相加运算
{
    BigNum t(*this);
    int i, big;      //位数
    big = T.len > len ? T.len : len;
    for (i = 0; i < big; i++)
    {
        t.a[i] += T.a[i];
        if (t.a[i] > MAXN)
        {
            t.a[i + 1]++;
            t.a[i] -= MAXN + 1;
        }
    }
    if (t.a[big] != 0)
        t.len = big + 1;
    else
        t.len = big;
    return t;
}
BigNum BigNum::operator-(const BigNum & T) const   //两个大数之间的相减运算
{
    int i, j, big;
    bool flag;
    BigNum t1, t2;
    if (*this>T)
    {
        t1 = *this;
        t2 = T;
        flag = 0;
    }
    else
    {
        t1 = T;
        t2 = *this;
        flag = 1;
    }
    big = t1.len;
    for (i = 0; i < big; i++)
    {
        if (t1.a[i] < t2.a[i])
        {
            j = i + 1;
            while (t1.a[j] == 0)
                j++;
            t1.a[j--]--;
            while (j > i)
                t1.a[j--] += MAXN;
            t1.a[i] += MAXN + 1 - t2.a[i];
        }
        else
            t1.a[i] -= t2.a[i];
    }
    t1.len = big;
    while (t1.a[len - 1] == 0 && t1.len > 1)
    {
        t1.len--;
        big--;
    }
    if (flag)
        t1.a[big - 1] = 0 - t1.a[big - 1];
    return t1;
}
BigNum BigNum::operator*(const BigNum & T) const   //两个大数之间的相乘运算
{
    BigNum ret;
    int i, j, up;
    int temp, temp1;
    for (i = 0; i < len; i++)
    {
        up = 0;
        for (j = 0; j < T.len; j++)
        {
            temp = a[i] * T.a[j] + ret.a[i + j] + up;
            if (temp > MAXN)
            {
                temp1 = temp - temp / (MAXN + 1) * (MAXN + 1);
                up = temp / (MAXN + 1);
                ret.a[i + j] = temp1;
            }
            else
            {
                up = 0;
                ret.a[i + j] = temp;
            }
        }
        if (up != 0)
            ret.a[i + j] = up;
    }
    ret.len = i + j;
    while (ret.a[ret.len - 1] == 0 && ret.len > 1)
        ret.len--;
    return ret;
}
BigNum BigNum::operator/(const int & b) const   //大数对一个整数进行相除运算
{
    BigNum ret;
    int i, down = 0;
    for (i = len - 1; i >= 0; i--)
    {
        ret.a[i] = (a[i] + down * (MAXN + 1)) / b;
        down = a[i] + down * (MAXN + 1) - ret.a[i] * b;
    }
    ret.len = len;
    while (ret.a[ret.len - 1] == 0 && ret.len > 1)
        ret.len--;
    return ret;
}
int BigNum::operator %(const int & b) const    //大数对一个int类型的变量进行取模运算
{
    int i, d = 0;
    for (i = len - 1; i >= 0; i--)
    {
        d = ((d * (MAXN + 1)) % b + a[i]) % b;
    }
    return d;
}
BigNum BigNum::operator^(const int & n) const    //大数的n次方运算
{
    BigNum t, ret(1);
    int i;
    if (n<0)
        exit(-1);
    if (n == 0)
        return 1;
    if (n == 1)
        return *this;
    int m = n;
    while (m>1)
    {
        t = *this;
        for (i = 1; i << 1 <= m; i <<= 1)
        {
            t = t*t;
        }
        m -= i;
        ret = ret*t;
        if (m == 1)
            ret = ret*(*this);
    }
    return ret;
}
bool BigNum::operator>(const BigNum & T) const   //大数和另一个大数的大小比较
{
    int ln;
    if (len > T.len)
        return true;
    else if (len == T.len)
    {
        ln = len - 1;
        while (a[ln] == T.a[ln] && ln >= 0)
            ln--;
        if (ln >= 0 && a[ln] > T.a[ln])
            return true;
        else
            return false;
    }
    else
        return false;
}
bool BigNum::operator >(const int & t) const    //大数和一个int类型的变量的大小比较
{
    BigNum b(t);
    return *this>b;
}
void BigNum::print()    //输出大数
{
    int i;
    cout << a[len - 1];
    for (i = len - 2; i >= 0; i--)
    {
        cout.width(DLEN);
        cout.fill('0');
        cout << a[i];
    }
}
void BigNum::printline() {
    print();
    puts("");
}

BigNum bnum[210];

void   init(){
  bnum[0]=1;
  bnum[1]=1;
  for(int i=2; i<210; i++)bnum[i]=bnum[i-1]+bnum[i-2];
}

int main(){
  init();
  int n;
  while(cin>>n){
    cout<<bnum[n]<<endl;
  }
  return 0;
}

题目:Problem C

链接:http://acm.hdu.edu.cn/showproblem.php?pid=5687

Problem C

   
 Accepts: 719
   
 Submissions: 5881
 Time Limit: 2000/1000 MS (Java/Others)
   
 Memory Limit: 131072/131072 K (Java/Others)
Problem Description

度熊手上有一本神奇的字典,你可以在它里面做如下三个操作:

1、insert : 往神奇字典中插入一个单词

2、delete: 在神奇字典中删除所有前缀等于给定字符串的单词

3、search: 查询是否在神奇字典中有一个字符串的前缀等于给定的字符串
Input

这里仅有一组测试数据。第一行输入一个正整数N(1≤N≤100000)N (1\leq N\leq 100000)N(1N100000),代表度熊对于字典的操作次数,接下来NNN行,每行包含两个字符串,中间中用空格隔开。第一个字符串代表了相关的操作(包括: insert, delete 或者 search)。第二个字符串代表了相关操作后指定的那个字符串,第二个字符串的长度不会超过30。第二个字符串仅由小写字母组成。

Output

对于每一个search 操作,如果在度熊的字典中存在给定的字符串为前缀的单词,则输出Yes 否则输出 No。

Sample Input
5
insert hello
insert hehe
search h
delete he
search hello
Sample Output
Yes
No
思路:trie树,删除的时候,sum-=getans(ch),将最后的那个标记改成0


#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define mod 1000000007
#define pi (4*atan(1.0))
const int N=5e5+10,M=5e6+10,inf=1e9+10;
int a[N][27],sum[M],len;
void init()
{
    memset(a,0,sizeof(a));
    memset(sum,0,sizeof(sum));
    len=1;
}
int getnum(char a)
{
    return a-'a';
}
void insertt(char *aa)
{
    int u=0,n=strlen(aa);
    for(int i=0; i<n; i++)
    {
        int num=getnum(aa[i]);
        if(!a[u][num])
        {
            a[u][num]=len++;
        }
        u=a[u][num];
        sum[u]++;
    }
}
void deletee(char *aa,int pa)
{
    int u=0,n=strlen(aa),num,gg;
    for(int i=0;i<n;i++)
    {
        num=getnum(aa[i]);
        if(!a[u][num])
        return;
        gg=u;
        u=a[u][num];
        sum[u]-=pa;
    }
    a[gg][num]=0;
    sum[u]-=pa;
}
int getans(char *aa)
{
    int u=0,x=strlen(aa);
    for(int i=0; i<x; i++)
    {
        int num=getnum(aa[i]);
        if(!a[u][num])
        return 0;
        u=a[u][num];
    }
    return sum[u];
}
char ch[100],gg[100];
int main()
{
    int x,y,z,i,t;
    init();
    scanf("%d",&x);
    for(i=0;i<x;i++)
    {
        scanf("%s%s",gg,ch);
        if(gg[0]=='i')
        insertt(ch);
        else if(gg[0]=='s')
        {
            if(getans(ch))
            printf("Yes\n");
            else
            printf("No\n");
        }
        else
        {
            deletee(ch,getans(ch));
        }
    }
    return 0;
}



题目:Problem D

链接:http://acm.hdu.edu.cn/showproblem.php?pid=5688


Problem D

   
 Accepts: 2614
   
 Submissions: 7849
 Time Limit: 2000/1000 MS (Java/Others)
   
 Memory Limit: 65536/65536 K (Java/Others)
Problem Description

度熊所居住的 D 国,是一个完全尊重人权的国度。以至于这个国家的所有人命名自己的名字都非常奇怪。一个人的名字由若干个字符组成,同样的,这些字符的全排列的结果中的每一个字符串,也都是这个人的名字。例如,如果一个人名字是 ACM,那么 AMC, CAM, MAC, MCA, 等也都是这个人的名字。在这个国家中,没有两个名字相同的人。

度熊想统计这个国家的人口数量,请帮助度熊设计一个程序,用来统计每一个人在之前被统计过多少次。

Input

这里包括一组测试数据,第一行包含一个正整数NNN,接下来的NNN 行代表了 NNN 个名字。NNN 不会超过100,000100,000100,000,他们的名字不会超过40位.

Output

对于每输入的一个人名,输出一个整数,代表这个人之前被统计了多少次。

Sample Input
5
ACM
MAC
BBA
ACM
BAB
Sample Output
0
1
0
2
1
把名字排序一下放到map里就好了
#include <bits/stdc++.h>
using  namespace  std;

map<string,int>mp;

int  main(){
  int n;
  cin>>n;
  while(n--){
    char s[50];
    scanf("%s",s);
    int len=strlen(s);
    sort(s,s+len);
    string tmp=s;
    printf("%d\n",mp[tmp]);
    mp[tmp]++;
  }
  return 0;
}



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值