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

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
Copy
2
ACMlove2015
1 11
8 10
1
testMessage
1 1
Sample Output
6891
9240
88
思路:最朴素的想法就是每次询问就把字符串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
#include
#define LL long long
#define mo 9973
using 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;iscanf("%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
1
3
5
Sample Output
1
3
8

Hint
如果序列是:(111)。可以构造出如下三个新序列:(111), (21), (12)。
思路:看见1,3,8不自觉的就想起了Fibonacc,接着推了推就肯定了。不过看数据量,所以需要用高精度。
#include
#include
#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
5
insert hello
insert hehe
search h
delete he
search hello
Sample Output
Yes
No
思路:看见这个前缀查找就很自然的想起了Trie树,这个题就是一个简单模板题。
#include
#include
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;iscanf("%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
5
ACM
MAC
BBA
ACM
BAB
Sample Output
0
1
0
2
1
思路:直接对每次读入的名字排序,然后map记录就ok.
#include
#include
#include
#include
using namespace std;
int main()
{
    int n;
    map<string,int> name_count;
    scanf("%d",&n);
    for(int i=0;ichar 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
4
a < 100
c > 99
b > 100 , b == 99 , c < 98
a < 1000, a >= 99
Sample Output
unique
1
unique
1 2
思路:这道题比较繁琐,是个模拟题。每一行的每个变量表示一个集合,某个变量集合为空,则整个语句都为空,否则各变量分别对应一个集合。
#include   
#include   
#include   
#include   
using namespace std;
#define INF 20000
struct Expr
{
    string var;
    int l,r;
    Expr()
    {
        this->l=-INF;
        this->r=INF;
    }
};
vector 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;iif(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;iif(!flag[i])continue;
        bool ok=true;
        for(int j=0;jfor(int p=0;pif(!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;iprintf("%d%c",result[i],i==len-1?'\n':' ');
    }
}
int main()
{
    int n;
    string str;
    scanf("%d",&n);
    for(int i=0;itrue;
    getline(cin,str);
    for(int i=0;icin,str);
        InitExpr(str,i);
    }
    return 0;
}

你可能感兴趣的:(ACM)