2016百度之星资格赛

Problem A

度熊手上有一本字典存储了大量的单词,有一次,他把所有单词组成了一个很长很长的字符串。现在麻烦来了,他忘记了原来的字符串都是什么,神奇的是他竟然记得原来那些字符串的哈希值。一个字符串的哈希值,由以下公式计算得到:
H(s)=ilen(s)i=1(Si28) (mod 9973)
Si 代表 S[i] 字符的 ASCII 码。
请帮助度熊计算大字符串中任意一段的哈希值是多少。

思路

预处理前缀积,询问时利用前缀相除,由于模是质数,求区间积时用乘法逆元代替除法运算

#include 
#include 
using namespace std;
const int mod = 9973;
int n, l, r, h[123456];
char s[123456];
int powermod(int a, int n, int m) {
    int r = 1;
    while (n) {
        if (n & 1) r = r * a % m;
        a = a * a % m;
        n >>= 1;
    }
    return r;
}
int main() {
    //freopen("in.txt", "r", stdin);
    while (cin >> n) {
        scanf("%s", s);
        h[0] = 1;
        for (int i = 0; s[i]; i++) {
            h[i + 1] = h[i] * (s[i] - 28) % mod;
        }
        for (int i = 0; i < n; i++) {
            scanf("%d%d", &l, &r);
            printf("%d\n", h[r] * powermod(h[l - 1], mod - 2, mod) % mod);
        }
    }
    return 0;
}

Problem B

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

思路

令f[n]表示n个1的答案,为了构成所有不同的序列,第n个字符有两个选择,分别是不合并和与前面一个合并,于是得到递推式: f[n]=f[n1]+f[n2] ,由于n可以达到200,所以需要用上大数。
代码在这

Problem C

度熊手上有一本神奇的字典,你可以在它里面做如下三个操作:
1、insert : 往神奇字典中插入一个单词
2、delete: 在神奇字典中删除所有前缀等于给定字符串的单词
3、search: 查询是否在神奇字典中有一个字符串的前缀等于给定的字符串

思路

根据delete和search操作不难发现要用字典树,查询时如果遍历整棵子树去找肯定是会超时的,需要用一个域保存每个节点表示的子树所包含单词数目,插入和删除时维护一下这个值,查询时直接找就行了,复杂度是 O(

#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
struct Node {
    int cnt;
    Node *next[26];
};
Node *root, *cur;
Node total[1200000];
int c, buf, n;
char id[10], s[40];
Node* newNode() {
    return total + c++;
}
void ins(char s[], int p) {
    int id = s[p] - 'a';
    if (!cur->next[id]) cur->next[id] = newNode();
    cur = cur->next[id];
    cur->cnt++;
    if (s[p + 1]) ins(s, p + 1);
}
void del(char s[], int p) {
    int id = s[p] - 'a';
    Node *bb;
    if (!s[p + 1]) {
        if (cur->next[id]) buf = cur->next[id]->cnt;
        else buf = 0;
        cur->next[id] = 0;
        return;
    }
    cur = cur->next[id];
    if (!cur) {
        buf = 0;
        return;
    }
    bb = cur;
    del(s, p + 1);
    bb->cnt -= buf;
}
void sea(char s[], int p) {
    int id = s[p] - 'a';
    cur = cur->next[id];
    if (!cur) {
        puts("No");
        return;
    }
    if (!s[p + 1]) {
        if (cur->cnt) puts("Yes");
        else puts("No");
        return;
    }
    else sea(s, p + 1);
}

int main() {
    //freopen("in.txt", "r", stdin);
    cin >> n;
    root = newNode();
    while (n--) {
        scanf("%s%s", id, s);
        cur = root;
        if (id[0] == 'i') {
            root->cnt++;
            ins(s, 0);
        }
        if (id[0] == 'd') {
            del(s, 0);
            root->cnt -= buf;
        }
        if (id[0] == 's') sea(s, 0);
    }

    return 0;
}

Problem D

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

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

思路

用排序将不同的排列映射到唯一表示,统计这个唯一表示的次数
…数据没改之前被数据范围吓了一跳,犹豫了半天决定还是要写几行代码试一试,居然过了

#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
int n, len;
char s[1234567];
map<string, int> mp;
int main() {
    //freopen("in.txt", "r", stdin);
    cin >> n;
    while (n--) {
        scanf("%s", s);
        len = strlen(s);
        sort(s, s + len);
        printf("%d\n", mp[s]);
        mp[s]++;
    }
    return 0;
}

Problem E

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

思路

这个题目的关键是判断两个复合条件是否交集非空,由于是取交集,那么相当于是把两个复合条件里的所有简单条件放一起进行与运算,看结果是否非空。进行与运算时不同变量分开处理,在处理同一个变量是否冲突时,5个关系也要分开,小于类关系取最小值,大于类关系取最大值,等于关系不能出现两个不同的运算数,这样把所有的简单条件变成了5个关系式,判断下这5个关系式是否冲突即可。

#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
map<string, int> mp;
int c;
struct Expr {
    int var, opt, num;
    Expr() {}
    Expr(int var, int opt, int num) {
        this->var = var;
        this->opt = opt;
        this->num = num;
    }
};
struct Inp {
    char s[12345], *p;
    Inp() {}
    void read() {
        gets(s);
        p = s;
    }
    bool hasNext() {
        while (*p) {
            if (*p++ == ',') return true;
        }
        return false;
    }
    bool isAlp(char ch) {return ch >= 'a' && ch <= 'z';}
    int nextVar() {
        char *buf;
        while (*p == ' ') p++;
        buf = p;
        while (isAlp(*p)) p++;
        return mp[string(buf, p - buf)]? mp[string(buf, p - buf)] : (mp[string(buf, p - buf)] = ++c);
    }
    int nextOpt() {
        char *buf;
        while (*p == ' ') p++;
        buf = p;
        while (*p == '<' || *p == '>' || *p == '=') p++;
        string s(buf, p - buf);
        if (s == "==") return 0;
        if (s == "<") return 1;
        if (s == ">") return 2;
        if (s == "<=") return 3;
        if (s == ">=") return 4;
    }
    int nextNum() {
        int ans = 0, flag = 0;
        while (*p == ' ') p++;
        while (isdigit(*p) || *p == '-') {
            if (isdigit(*p)) ans = ans * 10 + *p - '0';
            else flag = 1;
            p++;
        }
        return flag? -ans : ans;
    }
    Expr nextExp() {
        int a = nextVar(), b = nextOpt(), c = nextNum();
        return Expr(a, b, c);
    }
};
bool cmp(Expr a, Expr b) {
    return a.var == b.var? a.opt < b.opt : a.var < b.var;
}
int umin(int &a, int b) {if (a > b) a = b;}
int umax(int &a, int b) {if (a < b) a = b;}
struct Con {
    vector v;
    bool conflict, flag[33];
    int bound[33][5];
    void add(Con con) {
        int sz = con.v.size();
        for (int i = 0; i < sz; i++) {
            v.push_back(con.v[i]);
        }
    }
    void init() {
        for (int i = 0; i < 33; i++) {
            bound[i][0] = bound[i][1] = bound[i][3] = 12345;
            bound[i][2] = bound[i][4] = -12345;
        }
        int sz = v.size();
        for (int i = 0; i < sz; i++) {
            Expr cur = v[i];
            flag[cur.var] = true;
            if (upd(cur, bound[cur.var])) {
                conflict = true;
                break;
            }
        }
        if (!conflict && chk()) conflict = true;
    }
    bool upd(Expr cur, int a[]) {
        if (cur.opt == 0) {
            if (a[0] != 12345 && a[0] != cur.num) return true;
            a[0] = cur.num;
        }
        if (cur.opt == 1) umin(a[1], cur.num);
        if (cur.opt == 2) umax(a[2], cur.num);
        if (cur.opt == 3) umin(a[3], cur.num);
        if (cur.opt == 4) umax(a[4], cur.num);
        return false;
    }
    bool chk(int a[5]) {
        int minv = a[1], maxv = a[2];
        bool minf = 0, maxf = 0;
        if (a[3] < minv) {
            minv = a[3];
            minf = 1;
        }
        if (a[4] > maxv) {
            maxv = a[4];
            maxf = 1;
        }
        if (minf && maxf) {
            if (a[0] == 12345) return minv >= maxv;
            return a[0] <= minv && a[0] >= maxv;
        }
        if (minf && !maxf) {
            if (a[0] == 12345) return minv > maxv;
            return a[0] <= minv && a[0] > maxv;
        }
        if (!minf && maxf) {
            if (a[0] == 12345) return minv > maxv;
            return a[0] < minv && a[0] >= maxv;
        }
        if (!minf && !maxf) {
            if (a[0] == 12345) return minv > maxv + 1;
            return a[0] < minv && a[0] > maxv;
        }
    }
    bool chk() {
        for (int i = 1; i < 33; i++) {
            if (flag[i]) {
                if (!chk(bound[i])) return true;
            }
        }
        return false;
    }
};
Inp inp;
Con con[1234];
int n;
int main() {
    //freopen("in.txt", "r", stdin);
    cin >> n;
    getchar();
    for (int i = 1; i <= n; i++) {
        inp.read();
        con[i].v.push_back(inp.nextExp());
        while (inp.hasNext()) con[i].v.push_back(inp.nextExp());
        vector<int> ans;
        int n = i;
        for (int i = 1; i < n; i++) {
            Con newcon = con[n];
            newcon.add(con[i]);
            newcon.init();
            if (!newcon.conflict) ans.push_back(i);
        }
        int sz = ans.size();
        if (sz == 0) puts("unique");
        else {
            for (int i = 0; i < sz; i++) {
                printf("%d%c", ans[i], i == sz - 1? '\n' : ' ');
            }
        }
    }
    return 0;
}

你可能感兴趣的:(算法竞赛)