ACM学习历程—2016"百度之星" - 资格赛(Astar Round1)

http://bestcoder.hdu.edu.cn/contests/contest_show.php?cid=690

A题:

给定字符串,求任意区间的Hash值。

根据题目给定的Hash方式,属于乘法类型,那么就可以预处理出所有的乘法前缀,然后利用逆元,就可以得到任意区间的Hash值。

不过在这题上跪了好久,最后讨论版的一位大神给出了一个很叼的隐含条件:“同志们,当a, b超范围的时候,输出上一次询问的答案,亲测可行。。。太坑了。。。

代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <string>
#include <vector>
#define MOD 9973

using namespace std;

const int maxN = 1000005;
int q, len, ans, inv[10000], s[maxN];
char str[maxN];

void init()
{
    //***预处理所有i在质数MOD下的逆元
    inv[1] = 1;
    for (int i = 2; i < 10000; i++)
        inv[i] = inv[MOD%i]*(MOD-MOD/i) % MOD;
}

void input()
{
    scanf("%s", str);
    len = strlen(str);
    for (int i = 0; i < len; ++i)
    {
        if (i == 0) s[i] = (str[i]-28+MOD)%MOD;
        else s[i] = s[i-1]*(str[i]-28+MOD)%MOD;
    }
}

bool judge(int lt, int rt)
{
    if (lt > rt) return false;
    if (lt < 1 || lt > len) return false;
    if (rt < 1 || rt > len) return false;
    return true;
}

inline int getHash(int from, int to)
{
    return (from == 0 ? s[to] : s[to]*inv[s[from-1]]%MOD);
}

void work()
{
    int lt, rt;
    for (int i = 0; i < q; ++i)
    {
        scanf("%d%d", &lt, &rt);
        if (judge(lt, rt))
            ans = getHash(lt-1, rt-1);
        printf("%d\n", ans);
    }
}

int main()
{
    //freopen("test.in", "r", stdin);
    //freopen("test.out", "w", stdout);
    init();
    while (scanf("%d", &q) != EOF)
    {
        input();
        work();
    }
    return 0;
}
View Code

 

B题:

一个递推,如果有n个1,那么要么前两个1结合,要么不结合,那么p(n) = p(n-1)+p(n-2)。然后Java大数直接打表。

代码:

import java.math.BigInteger;
import java.util.Scanner;


public class Main
{
    BigInteger p[] = new BigInteger[205];
    
    void init()
    {
        p[1] = new BigInteger("1");
        p[2] = new BigInteger("2");
        for (int i = 3; i < 205; ++i)
            p[i] = p[i-1].add(p[i-2]);
    }
    
    public static void main(String[] args)
    {
        Scanner input = new Scanner(System.in);
        Main ans = new Main();
        int n = 0;
        ans.init();
        while (input.hasNext())
        {
            n = input.nextInt();
            System.out.println(ans.p[n]);
        }
    }
}
View Code

 

C题:

一道字符串前缀问题。

有三种操作,插入一个单词,删除给定前缀的所有单词,查询是否存在给定前缀的单词。

用字典树搞,插入的时候,给路径上所有结点的vis加1。

删除的时候,删除前缀后面的所有子树,并将路径上所有结点的vis值,减去最末结点的vis值。

查询时,一旦路径上有一个vis值为0,就查询失败。

代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <string>
#include <vector>

using namespace std;

struct Trie
{
    int vis;
    int next[26];
}tree[3000005];

int q, top;

void build()
{
    top = 0;
    for (int i = 0; i < 26; ++i) tree[0].next[i] = -1;
    tree[0].vis = 0;
}

int createNode()
{
    top++;
    for (int i = 0; i < 26; ++i) tree[top].next[i] = -1;
    tree[top].vis = 0;
    return top;
}

void add(char str[])
{
    int len = strlen(str), k, now = 0;
    for (int i = 0; i < len; ++i)
    {
        k = str[i]-'a';
        if (tree[now].next[k] == -1) tree[now].next[k] = createNode();
        now = tree[now].next[k];
        tree[now].vis++;
    }
}

void del(char str[])
{
    int len = strlen(str), k, now = 0, cnt;
    for (int i = 0; i < len; ++i)
    {
        k = str[i]-'a';
        if (tree[now].next[k] == -1) return;
        now = tree[now].next[k];
    }
    for (int i = 0; i < 26; ++i) tree[now].next[i] = -1;
    cnt = tree[now].vis;
    now = 0;
    for (int i = 0; i < len; ++i)
    {
        k = str[i]-'a';
        now = tree[now].next[k];
        tree[now].vis -= cnt;
    }
}

bool get(char str[])
{
    int len = strlen(str), k, now = 0;
    for (int i = 0; i < len; ++i)
    {
        k = str[i]-'a';
        if (tree[now].next[k] == -1) return false;
        now = tree[now].next[k];
        if (!tree[now].vis) return false;
    }
    return true;
}

void work()
{
    build();
    char op[20], str[40];
    for (int i = 0; i < q; ++i)
    {
        scanf("%s%s", op, str);
        switch (op[0])
        {
            case 'i':
                add(str);
                break;
            case 'd':
                del(str);
                break;
            case 's':
                if (get(str)) printf("Yes\n");
                else printf("No\n");
                break;
        }
    }
}

int main()
{
    //freopen("test.in", "r", stdin);
    //freopen("test.out", "w", stdout);
    while (scanf("%d", &q) != EOF)
        work();
    return 0;
}
View Code

 

D题:

这题直接排序+map能过。没试字典树。

代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <string>
#include <vector>

using namespace std;

int main()
{
    //freopen("test.in", "r", stdin);
    //freopen("test.out", "w", stdout);
    int n;
    char str[50];
    while (scanf("%d", &n) != EOF)
    {
        map<string, int> s;
        for (int i = 0; i < n; ++i)
        {
            scanf("%s", str);
            sort(str, str+strlen(str));
            printf("%d\n", s[str]++);
        }
    }
    return 0;
}
View Code

 

posted on 2016-05-17 18:08  AndyQsmart  阅读(263)  评论(0编辑  收藏  举报

导航