2016"百度之星" - 资格赛(Astar Round1)

来源:互联网 发布:notepad 安装sql插件 编辑:程序博客网 时间:2024/04/30 22:58

Problem A

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

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

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

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

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

Input

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

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

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

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

Output

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

Sample Input
2ACMlove20151 118 101testMessage1 1
Sample Output
6891924088
思路:最朴素的想法就是每次询问就把字符串copy出来,然后根据公式计算。但是时间复杂度明显是O(Nlen)所以会超时,我们可以发现有很多询问区间是重复的,所以可以选择先做预处理把结果先保存到一个数组中,由于要mod,所以要用到乘法逆元。
Ps:逆元 :(a/b) (mod N) = (a * x) (mod N)。 x表示b的逆元。并且 b*x ≡ 1 (mod N )  注意:只有当b与N互质的时候才存在逆元。一般情况下,ax+by=1;得 x为a mod  b 的逆元,y为 b mod a的逆元。
根据费马小定理,对于素数n,任意不是n的倍数的b,都有:   b^(N-1)=1(mod N)---->b*b^(N-2)=1(mod N)----->b的逆元为b^(N-2),
所以(a/b)mod N =(a*b^(N-2))mod N
#include<iostream>#include<stdio.h>#define LL long long#define mo 9973using namespace std;LL qmod(LL a,LL b){    LL sum=1;    while(b)    {        if(b&1) sum=(sum*a)%mo;        b>>=1;        a=(a*a)%mo;     }    return sum;}int main(){    int n,i,a,b;    string str;    LL s[100005];    while(scanf("%d",&n)!=EOF)    {        cin>>str;        s[0]=1;        for(long i=1;i<=str.length();i++)           s[i]=(s[i-1])*(str[i-1]-28)% mo;        for(int i=0;i<n;i++)        {            scanf("%d%d",&a,&b);            if(a>b) swap(a,b);            printf("%ld\n",(s[b]*(qmod(s[a-1],mo-2)%mo))%mo);        }    }    return 0;     }

Problem B

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

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

Input

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

1\leq N \leq 2001N200

Output

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

Sample Input
135
Sample Output
138
Hint
如果序列是:(111)。可以构造出如下三个新序列:(111), (21), (12)。
思路:看见1,3,8不自觉的就想起了Fibonacc,接着推了推就肯定了。不过看数据量,所以需要用高精度。
#include<stdio.h>#include<string.h>#define LL long long    LL a[205][100];void add(int p,int q){    int n1[100],n2[100],n3[100];    memset(n1, 0, sizeof(n1));    memset(n2, 0, sizeof(n2));    memset(n3, 0, sizeof(n3));    for(int i=0;i<=a[p][0];i++) n1[i]=a[p][i];    for(int i=0;i<=a[q][0];i++) n2[i]=a[q][i];    if(n1[0]>n2[0]) n3[0]=n1[0];    else n3[0]=n2[0];    for(int i=1;i<=n3[0];i++)    {        n3[i]+=n1[i]+n2[i];        n3[i+1]+=n3[i]/10;        n3[i]=n3[i]%10;    }    while(n3[n3[0]+1]!=0) n3[0]++;    a[p+1][0]=n3[0];    for(int i=1;i<=n3[0];i++) a[p+1][i]=n3[i];}int main(){    int n,i;    a[0][0]=0;    a[1][0]=1;a[1][1]=1;a[2][0]=1;a[2][1]=2;    for(i=3;i<=201;i++) add(i-1,i-2);    while(scanf("%d",&n)!=EOF)    {        for(int j=a[n][0];j>=1;j--) printf("%d",a[n][j]);        printf("\n");    }    return 0;}

Problem C

 
 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\leq N\leq 100000)N(1N100000),代表度熊对于字典的操作次数,接下来NN行,每行包含两个字符串,中间中用空格隔开。第一个字符串代表了相关的操作(包括: insert, delete 或者 search)。第二个字符串代表了相关操作后指定的那个字符串,第二个字符串的长度不会超过30。第二个字符串仅由小写字母组成。

Output

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

Sample Input
5insert helloinsert hehesearch hdelete hesearch hello
Sample Output
YesNo
思路:看见这个前缀查找就很自然的想起了Trie树,这个题就是一个简单模板题。
#include<stdio.h>#include<string>using namespace std;    typedef struct node{    int num;    node *next[30];    node()    {        memset(next,0,sizeof(next));        num=0;    }}Trie;void insert(node *root,string s){    node *p=root;    int i=0;    while(s[i])    {        int x=s[i]-'a';        if(p->next[x]==0) p->next[x]=new node();        p=p->next[x];        p->num++;        i++;    }}int search(node *root,string s){    node *p=root;    int i=0;    while(s[i])    {        int x=s[i]-'a';        if(p->next[x]==0) return 0;        p=p->next[x];        i++;    }    return p->num;}void delet(node *root,string s,int k){    node *p=root;    int i=0;    while(s[i])    {        int x=s[i]-'a';        p=p->next[x];        p->num-=k;        i++;    }    for(i=0;i<30;i++) p->next[i]=0;}int main(){    int i,n;    char s1[35],s2[35];    scanf("%d",&n);    Trie *root = new node();    for(i=0;i<n;i++)    {        scanf("%s%s",s1,s2);        if(s1[0]=='i') insert(root,s2);        else if(s1[0]=='d')         {            int k = search(root,s2);            if(k!=0) delet(root,s2,k);        }else if(s1[0]=='s')        {            int k = search(root,s2);            if(k!=0) printf("Yes\n");            else printf("No\n");        }    }    return 0;}

Problem D

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

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

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

Input

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

Output

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

Sample Input
5ACMMACBBAACMBAB
Sample Output
01021
思路:直接对每次读入的名字排序,然后map记录就ok.
#include<stdio.h>#include<algorithm>#include<map>#include<string>using namespace std;int main(){    int n;    map<string,int> name_count;    scanf("%d",&n);    for(int i=0;i<n;i++)    {        char s[45];        scanf("%s",s);        sort(s,s+strlen(s));        printf("%d\n",name_count[s]++);    }    return 0;}

Problem E

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

小度熊是一个尽职尽责的程序熊,每天产出数千行的代码,代码当中存在很多判断条件。度熊想让自己代码中的这些条件不存在交集。为了简化问题,一个条件可以是一个『简单条件』或者是一个『复合条件』,简单条件由『变量』、『比较符』和『运算数』组成,其中『变量』是用小写字符表示的一串字符,『运算数』仅为整数,『运算符』包括:<、>、<=、>=、==。分别代表:小于、大于、小于等于、大于等于和等于关系。简单条件的格式固定,左边为变量名,中间为操作符,右边为数字。若干个『简单条件』中间通过英文逗号组成一个『复合条件』,各『简单条件』之间是逻辑与的关系,例如:

简单条件: a > 100

复合条件: duxiong < 1000 , a > 100

Input

这里包括一组测试数据,第一行一个正整数 N(1 \leq N \leq 1000)N(1N1000),接下来 NN 行,每行一个条件,条件可能是一个『简单条件』或者是一个『复合条件』。其中『变量』不会超过30个字符,『运算数』的绝对值在10,000以内。测试数据中,不同变量的数量不会超过30个。其中『变量』、『比较符』和『运算数』 之前和之后都有可能出现若干空格字符。所有简单规则都是按照『变量』『比较符』『运算数』这样的顺序定义的,没有特例。

Output

对于第 ii 个条件,输出其与前 i-1i1个条件是否存在交集非空的情况。如果不存在交集非空的其他条件,输出一行字符串:『unique』。否则按照从小到大的顺序输出与其存在非空交集的条件的编号,编号之间用空格分隔,最后一个编号末尾不加空格。各条件从1-N1N编号。

Sample Input
4a < 100c > 99b > 100 , b == 99 , c < 98a < 1000, a >= 99
Sample Output
unique1unique1 2
思路:这道题比较繁琐,是个模拟题。每一行的每个变量表示一个集合,某个变量集合为空,则整个语句都为空,否则各变量分别对应一个集合。
#include <cstdio>  #include <string>  #include <vector>  #include <iostream>  using namespace std;#define INF 20000struct Expr{    string var;    int l,r;    Expr()    {        this->l=-INF;        this->r=INF;    }};vector<Expr> exprs[1005];bool flag[1005];void SkipSpace(const char *&str){    while(*str && (*str==' ')||(*str==',')) ++str;}bool GetMixedRange(int l1,int r1,int l2,int r2,int &l,int &r){    l=max(l1,l2);    r=min(r1,r2);    return l1<=l2;}void AddExpr(int k,Expr obj){    for(int i=0;i<exprs[k].size();i++)    {        if(exprs[k][i].var == obj.var)        {            int l,r;            if(GetMixedRange(exprs[k][i].l,exprs[k][i].r,            obj.l,obj.r,l,r))            {                exprs[k][i].l=l;                exprs[k][i].r=r;            }            else flag[k]=false;        }        return;    }    exprs[k].push_back(obj);}bool Judge(Expr &a,Expr &b){    if(a.var != b.var) return true;    int l=max(a.l,b.l),r=min(a.r,b.r);    return l<=r;}void InitExpr(string str,int k){    const char *s = str.c_str();    while(*s)    {        string var,opr;        int num=0;        SkipSpace(s);        while(isalpha(*s))        {            var+=*s;            ++s;        }        SkipSpace(s);        while(*s!=' '&&!isdigit(*s))        {            opr+=*s;            ++s;        }        SkipSpace(s);        while(*s&&isdigit(*s))        {            num=num*10+*s-'0';            ++s;        }        Expr obj;        obj.var = var;        if(opr =="<") obj.r=num-1;        else if(opr==">") obj.l=num+1;        else if(opr=="<=") obj.r=num;        else if(opr==">=") obj.l=num;        else if(opr=="==") obj.l=obj.r=num;        AddExpr(k,obj);        if(!flag[k])        {            printf("unique\n");            return;        }    }    vector<int> result;    for(int i=0;i<k;i++)    {        if(!flag[i])continue;        bool ok=true;        for(int j=0;j<exprs[i].size();j++)        {            for(int p=0;p<exprs[k].size();p++)            {                if(!Judge(exprs[i][j],exprs[k][p]))                {                    ok=false;                    break;                }            }            if(!ok) break;        }        if(ok) result.push_back(i+1);    }    int len=result.size();    if(len==0) puts("unique");    else    {        for(int i=0;i<len;i++)        printf("%d%c",result[i],i==len-1?'\n':' ');    }}int main(){    int n;    string str;    scanf("%d",&n);    for(int i=0;i<n;i++) flag[i]=true;    getline(cin,str);    for(int i=0;i<n;i++)    {        getline(cin,str);        InitExpr(str,i);    }    return 0;}

1 0
原创粉丝点击