2016百度之星

本文提供了编程挑战赛中四道题目的解决方案,涉及字符串哈希计算、斐波那契数列、Trie树应用及字符串全排列比较,通过实际代码展示了不同问题的有效解决方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Problem A

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


做的方法有很多,正解应该是乘法逆元,不过用区间线段树也能过。 题目数据有点坑,会出现左端点大于右端点的情况。建线段树的话虽然有点费时间空间不过不知道为什么还是能过。
贴代码吧,第一次打线段树。
/*
 * main.cpp
 *
 *  Created on: 2016年5月14日
 *      Author: Triose
 */
#include<stdio.h>
#include<iostream>
#include<string>
#include<string.h>
using namespace std;
//#define ONLINE_JUDGE
#define rep(i,a) for(int (i)=0; i<(a);(i)++)
#define mem(a,b) (memset((a),b,sizeof(a)))
#define sf(a) scanf("%d",&a)
#define sfI(a) scanf("%I64d",&a)
#define sfd(a,b) scanf("%d%d",&a,&b)
#define sft(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define sfs(a) scanf("%s",a)
#define pf(a) printf("%d\n",a)
#define pfd(a,b) printf("%d %d\n",a,b)
#define pfs(a) printf("%s\n",a)
#define pfI(a) printf("%I64d\n",a)
#define enter putchar(10)
#define LL __int64
template<class T> T gcd(T a, T b) { return b ? gcd(b, a%b) : a; }
template<class T> T lcm(T a, T b) { return a / gcd(a, b)*b; }
template<class T> inline T Min(T a, T b) { return a<b ? a : b; }
template<class T> inline T Max(T a, T b) { return a>b ? a : b; }
int n, m;
#define mod 9973
#define N 100010
char str[N];
struct Tree {
    int s,e;
    int data;
    Tree * left;
    Tree * right;
};
Tree * tree;

Tree * Build(Tree * root_,int s_, int e_) {
    if(s_ == e_) {
        if(!root_) {
            Tree * root = new Tree();
            root->data = str[s_] - 28;
            root->left = NULL; root->right = NULL;
            root->s = s_; root->e = e_;
            return root;
        }
        root_->data = str[s_] - 28;
        root_->s = s_; root_->e = e_;
        return root_;
    }
    if(!root_) {
        Tree * root = new Tree();
        root->s = s_; root->e = e_;
        int mid = (s_ + e_) >> 1;
        root->left = Build(root->left, s_, mid);
        root->right = Build(root->right, mid + 1, e_);
        root->data = ((root->left ? root->left->data : 1) * (root->right ? root->right->data : 1)) % mod;
        return root;
    }
    int mid = (s_ + e_) >> 1;
    root_->s = s_; root_->e = e_;
    root_->left = Build(root_->left, s_, mid);
    root_->right = Build(root_->right, mid + 1, e_);
    root_->data = ((root_->left ? root_->left->data : 1) * (root_->right ? root_->right->data : 1)) % mod;
    return root_;
}
int Query(Tree * root, int x, int y) {
    if(root->s == x && root->e == y) return root->data;
    if(root->right && root->right->s > y) {
        return Query(root->left, x, y);
    }
    else if(root->left && root->left->e < x) {
        return Query(root->right, x, y);
    }
    int mid = (root->s + root->e) >> 1;
    return ((Query(root->left, x, mid) * Query(root->right, mid + 1, y)) % mod);
}


int main() {
#ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
//    freopen("Out.txt", "w", stdout);
#endif
    while(~sf(n)) {
        sfs(str);
        int len = strlen(str);
        tree = Build(tree, 0, len - 1);
        int x, y;
        rep(i, n) {
            sfd(x,y);
            if(x >= 1 && x <= len && y >= 1 && y <= len && x <= y) {
                pf(Query(tree, --x, --y));
            }
        }
    }
    return 0;
}

Problem B

 
 Accepts: 2282
 
 Submissions: 8433
 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)。
水到不行,斐波那契,用大整数类吧。
/*
 * main.cpp
 *
 *  Created on: 2016年5月14日
 *      Author: Triose
 */
#include<stdio.h>
#include<iostream>
#include<string>
#include<string.h>
#include<algorithm>
#include<vector>
#include<queue>
#include<stack>
#include<iterator>
#include<math.h>
#include<stdlib.h>
#include<map>
#include<set>
using namespace std;
//#define ONLINE_JUDGE
#define eps 1e-8
#define INF 0x7fffffff
#define inf 0x3f3f3f3f
#define rep(i,a) for(int (i)=0; i<(a);(i)++)
#define mem(a,b) (memset((a),b,sizeof(a)))
#define sf(a) scanf("%d",&a)
#define sfI(a) scanf("%I64d",&a)
#define sfd(a,b) scanf("%d%d",&a,&b)
#define sft(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define sfs(a) scanf("%s",a)
#define pf(a) printf("%d\n",a)
#define pfd(a,b) printf("%d %d\n",a,b)
#define pfs(a) printf("%s\n",a)
#define pfI(a) printf("%I64d\n",a)
#define enter putchar(10)
#define LL __int64
const double PI = acos(-1.0);
const double E = exp(1.0);
template<class T> T gcd(T a, T b) { return b ? gcd(b, a%b) : a; }
template<class T> T lcm(T a, T b) { return a / gcd(a, b)*b; }
template<class T> inline T Min(T a, T b) { return a<b ? a : b; }
template<class T> inline T Max(T a, T b) { return a>b ? a : b; }
int n, m;


typedef int hugeint;
const int Base = 100000;
const int Capacity = 100000;
struct xnum
{   int Len;int Data[Capacity];xnum() : Len(0) {}
    xnum(const xnum&V):Len(V.Len) {memcpy(Data,V.Data,Len*sizeof *Data);}
    xnum(int V) : Len(0) {
        for (; V > 0; V /= Base) Data[Len++] = V % Base;}
    xnum(char S[]);
    xnum& operator=(const xnum& V) {
        Len = V.Len;memcpy(Data, V.Data, Len * sizeof *Data);
        return *this; }
    int& operator[](int Index) { return Data[Index]; }
    int operator[](int Index) const { return Data[Index]; }
    void print(){
        printf("%d",Len==0?0:Data[Len-1]);
        for(int i=Len-2;i>=0;i--)
            for(int j=Base/10;j>0;j/=10)printf("%d",Data[i]/j%10);}};
xnum::xnum(char S[])
{   int I, J;Data[Len = 0] = 0;J = 1;
    for (I = strlen(S)-1; I>=0; I--) {
        Data[Len] += (S[I] - '0') * J;J *= 10;
        if (J >= Base) J = 1, Data[++Len] = 0;}
    if (Data[Len] > 0) Len++;}
int compare(const xnum& A, const xnum& B)
{   int I;
    if (A.Len != B.Len) return A.Len > B.Len ? 1 : -1;
    for (I = A.Len - 1; I >= 0 && A[I] == B[I]; I--);
    if (I < 0) return 0;
    return A[I] > B[I] ? 1 : -1;}
xnum operator+(const xnum& A, const xnum& B)
{   xnum R;int I;int Carry = 0;
    for (I = 0; I < A.Len || I < B.Len || Carry > 0; I++)
    {   if (I < A.Len) Carry += A[I];
        if (I < B.Len) Carry += B[I];
        R[I] = Carry % Base;Carry /= Base;}R.Len = I;return R;}
xnum operator-(const xnum& A, const xnum& B)
{   xnum R;int Carry = 0;R.Len = A.Len;  int I;
    for (I = 0; I < R.Len; I++)
    {   R[I] = A[I] - Carry;
        if (I < B.Len) R[I] -= B[I];
        if (R[I] < 0) Carry = 1, R[I] += Base;
        else Carry = 0;}
    while (R.Len > 0 && R[R.Len - 1] == 0) R.Len--;
return R;}
xnum operator*(const xnum& A, const int B)
{   int I;if (B == 0) return 0;
    xnum R;hugeint Carry = 0;
    for (I = 0; I < A.Len || Carry > 0; I++)
    {   if (I < A.Len) Carry += hugeint(A[I]) * B;R[I] = Carry % Base;
        Carry /= Base;}R.Len = I;return R;}
xnum operator*(const xnum& A, const xnum& B)
{   int I;
    if (B.Len == 0) return 0;
    xnum R;
    for (I = 0; I < A.Len; I++)
    {   hugeint Carry = 0;
        for (int J = 0; J < B.Len || Carry > 0; J++)
        {   if (J < B.Len) Carry += hugeint(A[I]) * B[J];
            if (I + J < R.Len) Carry += R[I + J];
            if (I + J >= R.Len) R[R.Len++] = Carry % Base;
            else R[I + J] = Carry % Base;Carry /= Base;} }return R;}
xnum operator/(const xnum& A, const int B)
{   xnum R;int I;hugeint C = 0;
    for (I = A.Len - 1; I >= 0; I--){C = C * Base + A[I];R[I] = C / B;C %= B;}
    R.Len = A.Len;
    while (R.Len > 0 && R[R.Len - 1] == 0) R.Len--;
    return R;}//div
xnum operator/(const xnum& A, const xnum& B)
{   int I;xnum R, Carry = 0;int Left, Right, Mid;
    for (I = A.Len - 1; I >= 0; I--)
    {   Carry = Carry * Base + A[I];Left = 0;Right = Base - 1;
        while (Left < Right)
        {   Mid = (Left + Right + 1) / 2;
            if (compare(B * Mid, Carry) <= 0) Left = Mid;
            else Right = Mid - 1;}
        R[I] = Left;Carry = Carry - B * Left;}R.Len = A.Len;
    while (R.Len > 0 && R[R.Len - 1] == 0) R.Len--;
    return R;}//mod
xnum operator%(const xnum& A, const xnum& B)
{    int I;xnum R, Carry = 0;int Left, Right, Mid;
    for (I = A.Len - 1; I >= 0; I--)
    {  Carry = Carry * Base + A[I];Left = 0;Right = Base - 1;
        while (Left < Right)
        { Mid = (Left + Right + 1) / 2;
            if (compare(B * Mid, Carry) <= 0) Left = Mid;
            else Right = Mid - 1;}
        R[I] = Left;Carry = Carry - B * Left;}R.Len = A.Len;
    while (R.Len > 0 && R[R.Len - 1] == 0) R.Len--;
    return Carry;}
istream& operator>>(istream& In, xnum& V)
{   char Ch;
    for (V = 0; In >> Ch;)
    {   V = V * 10 + (Ch - '0');
        if (cin.peek() <= ' ') break;}
    return In;}
ostream& operator<<(ostream& Out, const xnum& V)
{   int I;Out << (V.Len == 0 ? 0 : V[V.Len - 1]);
    for (I = V.Len - 2; I >= 0; I--)
        for (int J = Base / 10; J > 0; J /= 10) Out << V[I] / J % 10;
        return Out;}


#define N 210
xnum ans[N];
void Init() {
    ans[1] = 1; ans[2] = 2;
    for(int i = 3; i < N; i++) {
        ans[i] = ans[i - 1]    + ans[i - 2];
    }
}
int main() {
#ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
//    freopen("Out.txt", "w", stdout);
#endif
    Init();
    while(cin >> n) {
        if(!n) {
            putchar(10);continue;
        }
        cout << ans[n] << endl;
    }
    return 0;
}


Problem C

 
 Accepts: 724
 
 Submissions: 5931
 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树呗。第一次打trie树。打得很啰嗦,因为特别烦。
/*
 * main.cpp
 *
 *  Created on: 2016年5月14日
 *      Author: Triose
 */
#include<stdio.h>
#include<iostream>
#include<string>
#include<string.h>
using namespace std;
//#define ONLINE_JUDGE
#define rep(i,a) for(int (i)=0; i<(a);(i)++)
#define mem(a,b) (memset((a),b,sizeof(a)))
#define sf(a) scanf("%d",&a)
#define sfI(a) scanf("%I64d",&a)
#define sfd(a,b) scanf("%d%d",&a,&b)
#define sft(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define sfs(a) scanf("%s",a)
#define pf(a) printf("%d\n",a)
#define pfd(a,b) printf("%d %d\n",a,b)
#define pfs(a) printf("%s\n",a)
#define pfI(a) printf("%I64d\n",a)
#define enter putchar(10)
#define LL __int64
template<class T> T gcd(T a, T b) { return b ? gcd(b, a%b) : a; }
template<class T> T lcm(T a, T b) { return a / gcd(a, b)*b; }
template<class T> inline T Min(T a, T b) { return a<b ? a : b; }
template<class T> inline T Max(T a, T b) { return a>b ? a : b; }
int n, m;

#define MAX_SON 26
#define BASE 'a'
struct Trie {
    char ch;
    int family;
    Trie * next[MAX_SON];
    Trie(char ch = '*') {
        this->ch = ch;
        this->family = 0;
        rep(i, MAX_SON) this->next[i] = NULL;
    }
};

Trie * tree;

void Init() {
    if(!tree) tree = new Trie();
}

void ins(char *s) {
    Trie * tptr = tree;
    tptr->family++;
    while((*s) != '\0') {
        if(!tptr->next[(*s) - BASE]) {
            tptr->next[(*s) - BASE] = new Trie (*s);
        }
        tptr = tptr->next[(*s) - BASE];
        tptr->family++;
        s++;
    }
    return ;
}

bool search(char *s) {
    Trie * tptr = tree;
    while((*s) != '\0') {
        tptr = tptr->next[(*s) - BASE];
        if(!tptr || tptr->family == 0) return false;
        s++;
    }
    return tptr->family ? true : false;
}

void rem_del(Trie * root) {
    if(!root) return ;
    rep(i, MAX_SON) {
        if(root->next[i]) rem_del(root->next[i]);
    }
    delete root;
    return ;
}

void del(char *s) {
    Trie * tptr = tree;
    int len = strlen(s);
    rep(i, len) {
        tptr = tptr->next[(s[i] - BASE)];
        if(!tptr || tptr->family == 0) return ;
    }
    Trie * root = tree;
    while(root != tptr && (*s) != '\0') {
        root->family -= tptr->family;
        if(root->next[(*s) - BASE] == tptr) {
            root->next[(*s) - BASE] = NULL;
            break;
        }
        root = root->next[(*s) - BASE];
        s++;
    }
    rem_del(tptr);
}

int main() {
#ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
//    freopen("Out.txt", "w", stdout);
#endif
    int t;
    char con[30], str[40];
    while(~sf(t)) {
        Init();
        rep(i, t) {
            sfs(con); sfs(str);
            if(strcmp(con, "insert") == 0) {
                ins(str);
            }
            else if(strcmp(con, "search") == 0) {
                if(search(str)) {
                    pfs("Yes");
                }
                else {
                    pfs("No");
                }
            }
            else if(strcmp(con, "delete") == 0) {
                del(str);
            }
        }
    }
    rem_del(tree);
    return 0;
}

Problem D

 
 Accepts: 2649
 
 Submissions: 7934
 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映射吧。反正字符长度不长,排个序也没太大关系
/*
 * main.cpp
 *
 *  Created on: 2016年5月14日
 *      Author: Triose
 */
#include<stdio.h>
#include<iostream>
#include<string>
#include<string.h>
#include<algorithm>
#include<vector>
#include<queue>
#include<stack>
#include<iterator>
#include<math.h>
#include<stdlib.h>
#include<map>
#include<set>
using namespace std;
//#define ONLINE_JUDGE
#define eps 1e-8
#define INF 0x7fffffff
#define inf 0x3f3f3f3f
#define rep(i,a) for(int (i)=0; i<(a);(i)++)
#define mem(a,b) (memset((a),b,sizeof(a)))
#define sf(a) scanf("%d",&a)
#define sfI(a) scanf("%I64d",&a)
#define sfd(a,b) scanf("%d%d",&a,&b)
#define sft(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define sfs(a) scanf("%s",a)
#define pf(a) printf("%d\n",a)
#define pfd(a,b) printf("%d %d\n",a,b)
#define pfs(a) printf("%s\n",a)
#define pfI(a) printf("%I64d\n",a)
#define enter putchar(10)
#define LL __int64
const double PI = acos(-1.0);
const double E = exp(1.0);
template<class T> T gcd(T a, T b) { return b ? gcd(b, a%b) : a; }
template<class T> T lcm(T a, T b) { return a / gcd(a, b)*b; }
template<class T> inline T Min(T a, T b) { return a<b ? a : b; }
template<class T> inline T Max(T a, T b) { return a>b ? a : b; }
int n, m;
#define N 1000010
int ans[N];
map<string, int> mp;
int main() {
#ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
//    freopen("Out.txt", "w", stdout);
#endif
    int _;
    string tmp;
    while(cin >> _) {
        mp.clear();
        rep(i, _) {
            cin >> tmp;
            sort(tmp.begin(), tmp.end());
            ans[i] = mp[tmp]++;
        }
        rep(i, _) {
            cout << ans[i] << endl;
        }
    }
    return 0;
}

第五题懒得看了,后天还要考试。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值