【2016百度之星Astar Round1】【线段树/乘法逆元/高精度斐波那契/字典树/STL之map/最小表示法】

题目链接:http://bestcoder.hdu.edu.cn/contests/contest_show.php?cid=690

注意了,似乎航电的重挂数据有点离谱。。。。醉了。。。线段树也过不了了,不知道其他题怎么样。。。

Problem A

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
2
ACMlove2015
1 11
8 10
1
testMessage
1 1
Sample Output
6891
9240
88

单点更新区间查询线段树AC代码:

#include
#include
#include
#define mod 9973
using namespace std;
const int N=100005;
char s[N];
struct node
{
    int l,r,v;
}node[N<<2];
int cnt=0;
void build(int l,int r,int rt)
{
    node[rt].l=l;
    node[rt].r=r;
    node[rt].v=1;
    if(l==r){
        node[rt].v=(int)s[cnt++]-28;
        return;
    }
    int mid=(l+r)>>1;
    build(l,mid,rt<<1);
    build(mid+1,r,rt<<1|1);
    node[rt].v=(node[rt<<1].v*node[rt<<1|1].v)%mod;
}
void Insert(int p,int t,int rt)
{
    if(node[rt].l==node[rt].r&&p==node[rt].l){
        node[rt].v=t;
        return ;
    }
    int mid=(node[rt].l+node[rt].r)>>1;
    if(p<=mid) Insert(p,t,rt<<1);
    else Insert(p,t,rt<<1|1);
    node[rt].v=(node[rt<<1].v*node[rt<<1|1].v)%mod;
}
int query(int l,int r,int rt)       //  注意,这里是区间更新;之前写成了单点更新,TLE到死啊。。。
{
    if(node[rt].l==l&&r==node[rt].r)
        return node[rt].v;
    int mid=(node[rt].l+node[rt].r)>>1;
    if(r<=mid) return query(l,r,rt<<1);
    else if(l>mid) return query(l,r,rt<<1|1);
    else return query(l,mid,rt<<1)*query(mid+1,r,rt<<1|1)%mod;
}
int main()
{
    int t;
    int l,r;
    while(~scanf("%d",&t)){
        scanf("%s",s);
        int n=strlen(s);
        cnt=0;
        build(1,n,1);
        while(t--){
            scanf("%d%d",&l,&r);
            printf("%d\n",query(l,r,1));
        }
    }
    return 0;
}

两种逆元方法AC代码:

#include
#include
#include
#define LL __int64
#define mod 9973
using namespace std;
LL inv[100010]={0};
char s[100100];
LL H[100100];
//  计算逆元方法一:
LL mod_pow(LL x, LL n) {
    LL res = 1;
    while(n) {
        if(n & 1) res = res * x % mod;
        x = x * x % mod;
        n >>= 1;
    }
    return res%mod;
}
int main()
{
    inv[1]=1;
    inv[0]=1;
    //  计算逆元方法二:
    for(int i=2;i

Problem B

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)。

高精度斐波那契AC代码:

#include
#include
#include
using namespace std;
string s[201];
string add(string a,string b)
{
    string ans="";
    int aa[1000]={0},bb[1000]={0};
    int aLen=a.size();
    int bLen=b.size();
    int MaxLen=max(aLen,bLen);
    for(int i=0;i=0;i--)
        ans+=aa[i]+'0';
    return ans;
}
int main()
{
    int n;
    s[0]="1",s[1]="1";
    for(int i=2;i<201;i++){
        s[i]=add(s[i-1],s[i-2]);
    }
    while(cin>>n){
        cout<
天啦噜,更新一波,大家看仔细了,这两个代码有什么区别,前一个昨晚好好的AStar上AC今天死活WA...无奈,找队友AC代码对数据。。。
s[0]="";n=0竟然是正整数,也符合条件1<=n<=200,长知识了。。。。醉了,n=0输出为空。。。
#include
#include
#include
using namespace std;
string s[205];
string add(string a,string b)
{
    string ans="";
    int aa[1000]={0},bb[1000]={0};
    int aLen=a.size();
    int bLen=b.size();
    int MaxLen=max(aLen,bLen);
    for(int i=0;i=0;i--)
        ans+=aa[i]+'0';
    return ans;
}
int main()
{
    int n;
    //freopen("out.txt","w",stdout);
    s[0]="1",s[1]="1";
    for(int i=2;i<202;i++){
        s[i]=add(s[i-1],s[i-2]);
    }
    s[0]="";
    //for(int i=1;i<=200;i++)
    while(cin>>n){
            //cout<


Problem C

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
Copy
Yes
No

字典树AC代码:

#include
#include
#include
const int N=26;
struct node{
    int flag;   //  记录该单词出现的次数;
    node *next[N];
    node(){
        flag=0;
        memset(next,0,sizeof(next));
    }
};
node *p,*pre,*head=new node();
void Insert(char s[])
{
    p=head;
    int i=0;
    while(s[i]){
        int id=s[i++]-'a';
        if(p->next[id]==NULL) p->next[id]=new node();
        p=p->next[id];
        p->flag++;      //  标记该分支字母出现的个数;
    }
    //p->flag++;       //  标记改单词出现过,并且记录出现的次数;
}
//  返回该单词出现的次数;
int Query(char s[])
{
    p=head;
    int i=0;
    while(s[i]){
        int id=s[i++]-'a';
        if(p->next[id]==NULL) return 0;
        p=p->next[id];
    }
    return p->flag;
}
//  不能删除,删除会导致TLE,不删除容易出现内存泄漏MLE
int deal(node *T)
{
    for(int i=0;inext[i]!=NULL)
            deal(T->next[i]);
    }
    free(T);
    return 0;
}
//  该单词的计数-cnt;
void Deal(char s[],int cnt)
{
    p=head;
    int i=0;
    while(s[i]){
        int id=s[i++]-'a';
        p=p->next[id];
        p->flag-=cnt;
    }
    for(int i=0;inext[i]=NULL;
    }
    //deal(p);
    return ;
}
int main()
{
    int n;
    char s1[35],s2[35];
    while(~scanf("%d",&n)){
        head=new node();
        for(int i=0;i

Problem D

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

STLmap映射大法AC代码:

#include
#include
#include
using namespace std;
int main()
{
    string s;
    int n;
    cin.sync_with_stdio(false);
    while(cin>>n){
        mapMap;
        for(int i=0;i>s;
            sort(s.begin(),s.end());
            cout<

最小表示法未AC代码:

按道理是应该华丽的AC的,但是就是没有AC,也不知道是为什么。。。醉了
#include
#include
#include
using namespace std;
int minP(string s,int len)
{
    int i=0,j=1,k=0;
    while(i0) i+=k+1; //  j开始的位置更小;
            else j+=k+1;    //  i开始的位置更小或者相等;
            if(i==j) j++;
            k=0;        //  连续相同的个数置为0;
        }
    }
    return min(i,j);
}
int main()
{
    string s;
    int n;
    cin.sync_with_stdio(false);
    while(cin>>n){
        mapMap;
        for(int i=0;i>s;
            int len=s.size();
            s+=s;
            int t=minP(s,len);
            s=s.substr(t,len);
            cout<

Problem E

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
还不会。。。


你可能感兴趣的:(百度之星Astar)