首页 > 代码库 > 2016"百度之星" - 初赛(Astar Round2A)

2016"百度之星" - 初赛(Astar Round2A)

All X[HDU5690]

  找循环节,注意可能是混循环。

技术分享
#include <stdio.h>#include <string.h>bool f[10005];int a[10005], l, r;int main() {    int n, x, k, c, t;    long long m;    scanf("%d", &n);    for (int q = 0; q < n; q++) {        scanf("%d%lld%d%d", &x, &m, &k, &c);        memset(f, false, sizeof(f));        l = r = 0;        a[r++] = x % k;        f[a[0]] = true;        for (int i = 0;; i++) {            t = (a[r - 1] * 10 + x) % k;            if (f[t]) {                for (int j = 0; j < r; j++) {                    if (a[j] == t) {                        l = j;                        break;                    }                }                break;            }            f[t] = true;            a[r++] = t;        }        m -= l;        printf("Case #%d:\n%s\n", q + 1, c == a[m % (r - l) == 0 ? r - 1 : l + (int)(m % (r - l)) - 1] ? "Yes" : "No");    }    return 0;}
View Code

 Sitting in Line[HDU5691]

  状态压缩,状态i表示整数的选取状态,其二进制形式的10分别表示对应的数字是否选取。dp[i][j]表示在状态i下最后放置的数字是第j个数字能得到的最大值。

技术分享
#include<bitset>#include<map>#include<vector>#include<cstdio>#include<iostream>#include<cstring>#include<string>#include<algorithm>#include<cmath>#include<stack>#include<queue>#include<set>#define inf 0x3f3f3f3f#define mem(a,x) memset(a,x,sizeof(a))#define F first#define S secondusing namespace std;typedef long long ll;typedef pair<int, int> pii;inline int in() {    int res = 0;    char c;    int f = 1;    while ((c = getchar()) < 0 || c > 9)if (c == -) {            f = -1;        }    while (c >= 0 && c <= 9) {        res = res * 10 + c - 0, c = getchar();    }    return res * f;}const int N = 100010, MOD = 1e9 + 7;int a[16];int dp[1 << 16][16], must[16];int one[1 << 16];int main() {    for (int i = 0; i < 1 << 16; i++) {        for (int j = i; j; j >>= 1) {            one[i] += j & 1;        }    }    int T = in(), ca = 1;    while (T--) {        int n = in();        mem(must, -1);        int x, y;        for (int i = 0; i < n; i++) {            scanf("%d%d", &x, &y);            a[i] = x;            if (y != -1) {                must[y] = i;    //y位置必须是ai值            }        }        int all = 1 << n;        for (int i = 0; i < all; i++) {            for (int j = 0; j < n; j++) {                dp[i][j] = -inf;            }        }        //0没法转移, 特殊处理        if (must[0] == -1) {            for (int i = 0; i < n; i++) {                dp[1 << i][i] = 0;            }        } else {            dp[1 << must[0]][must[0]] = 0;        }        for (int i = 1; i < all; i++) {            int num = one[i];            if (must[num] == -1) {                for (int j = 0; j < n; j++) { //枚举结束位置                    if (i & 1 << j && dp[i][j] != -inf) {                        for (int k = 0; k < n; k++) { //枚举下一次加的值                            if (!(i & 1 << k)) {                                dp[i | 1 << k][k] = max(dp[i | 1 << k][k], dp[i][j] + a[k] * a[j]);                            }                        }                    }                }            } else {                int k = must[num]; //下一个位置必须是a[k]                if (i & 1 << k) {                    continue;    //如果a[k]已经使用, 不更新                }                for (int j = 0; j < n; j++) {                    if (i & 1 << j && dp[i][j] != -inf) {                        dp[i | 1 << k][k] = max(dp[i | 1 << k][k], dp[i][j] + a[j] * a[k]);                    }                }            }        }        int ans = -inf;        for (int j = 0; j < n; j++) {            ans = max(ans, dp[all - 1][j]);        }        printf("Case #%d:\n%d\n", ca++, ans);    }    return 0;}
View Code

Snacks[HDU5692]

  首先先弄成以0为根的一棵树,每个节点的权值为根节点到当前节点的价值之和。查询某个节点时,其价值之和的最大值应为该节点对应的子树中最大的权值。更新某个节点的权值时,则该节点对应的子树上每一个节点都会产生同样的变化。因此,可以通过dfs产生树的先根遍历,然后用线段树来进行更新和查询操作。

  错的原因:线段树写错了,lazy处理的不对。

技术分享
#pragma comment(linker, "/STACK:1024000000,1024000000")#include <stdio.h>#include <string.h>template <class T> class SegmentTree {public:    T dat, lazy;    int leftBorder, rightBorder, mid;    SegmentTree * leftSon, * rightSon;    T(* lazyfunc)(T, T);    T(* mergefunc)(T, T);    SegmentTree() {        leftBorder = rightBorder = -1;        leftSon = rightSon = NULL;    }    void pushdown();    void pushup();    void Build(T *, int, int, T(*)(T, T), T(*)(T, T));    void Modify(int, int, T);    T Query(int, int);    void Free();};template<class T> void SegmentTree<T>::pushdown() {    if (lazy && leftBorder != rightBorder) {        leftSon->dat = lazyfunc(leftSon->dat, lazy);        rightSon->dat = lazyfunc(rightSon->dat, lazy);        leftSon->lazy = lazyfunc(leftSon->lazy, lazy);        rightSon->lazy = lazyfunc(rightSon->lazy, lazy);    }    lazy = (T)0;}template<class T> void SegmentTree<T>::pushup() {    dat = mergefunc(leftSon->dat, rightSon->dat);}template<class T> void SegmentTree<T>::Build(T * S, int l, int r, T(* lfunc)(T, T), T(* mfunc)(T, T)) {    if (l > r) {        return;    }    lazy = (T)0;    leftBorder = l;    rightBorder = r;    mid = (leftBorder + rightBorder) >> 1;    lazyfunc = lfunc;    mergefunc = mfunc;    if (l == r) {        dat = S[l];        return;    }    leftSon = new SegmentTree;    leftSon->Build(S, l, mid, lfunc, mfunc);    rightSon = new SegmentTree;    rightSon->Build(S, mid + 1, r, lfunc, mfunc);    pushup();}template<class T> void SegmentTree<T>::Modify(int l, int r, T NewDat) {    if (l > r || l < leftBorder || rightBorder < r) {        return;    }    if (leftBorder == l && rightBorder == r) {        dat = lazyfunc(dat, NewDat);        lazy = lazyfunc(lazy, NewDat);        return;    }    pushdown();    if (r <= mid) {        leftSon->Modify(l, r, NewDat);    } else if (mid < l) {        rightSon->Modify(l, r, NewDat);    } else {        leftSon->Modify(l, mid, NewDat);        rightSon->Modify(mid + 1, r, NewDat);    }    pushup();}template<class T> T SegmentTree<T>::Query(int l, int r) {    if (l > r || l < leftBorder || rightBorder < r) {        return dat;    }    pushdown();    if (l == leftBorder && r == rightBorder) {        return dat;    }    if (r <= mid) {        return leftSon->Query(l, r);    } else if (mid < l) {        return rightSon->Query(l, r);    } else {        return mergefunc(leftSon->Query(l, mid), rightSon->Query(mid + 1, r));    }}template<class T> void SegmentTree<T>::Free() {    if (leftSon != NULL) {        leftSon->Free();    }    if (rightSon != NULL) {        rightSon->Free();    }    delete leftSon;    delete rightSon;}SegmentTree<long long> st;long long a[100005], b[100005], w[100005];int M, N;int head[100005], l[100005], r[100005];struct EDGE {    int v, nex;} edge[200005];void addEdge(int a, int b) {    edge[M].v = b;    edge[M].nex = head[a];    head[a] = M++;    edge[M].v = a;    edge[M].nex = head[b];    head[b] = M++;}long long lazyfunc(long long x, long long y) {    return x + y;}long long mergefunc(long long x, long long y) {    return x > y ? x : y;}void dfs1(int f, int x) {    int e = head[x];    while (e != -1) {        int v = edge[e].v;        if (f != v) {            a[v] = a[x] + w[v];            dfs1(x, v);        }        e = edge[e].nex;    }}void dfs2(int f, int x) {    l[x] = N;    b[N++] = a[x];    int e = head[x];    while (e != -1) {        int v = edge[e].v;        if (f != v) {            dfs2(x, v);        }        e = edge[e].nex;    }    r[x] = N - 1;}int main() {    int n, m, t, o, u, v;    scanf("%d", &t);    for (int q = 1; q <= t; q++) {        scanf("%d%d", &n, &m);        M = 0;        memset(head, -1, sizeof(head));        for (int i = 1; i < n; i++) {            scanf("%d%d", &u, &v);            addEdge(u, v);        }        for (int i = 0; i < n; i++) {            scanf("%lld", &w[i]);        }        a[0] = w[0];        dfs1(-1, 0);        N = 0;        dfs2(-1, 0);        st.Free();        st.Build(b, 0, N - 1, lazyfunc, mergefunc);        printf("Case #%d:\n", q);        for (int i = 0; i < m; i++) {            scanf("%d", &o);            if (o == 0) {                scanf("%d%d", &u, &v);                st.Modify(l[u], r[u], v - w[u]);                w[u] = v;            } else {                scanf("%d", &u);                printf("%lld\n", st.Query(l[u], r[u]));            }        }    }    return 0;}
View Code

D game[HDU5693]

  首先只用考虑长度为2和3的等差数列就可以了,因为更长的等差数列都可以拆成几个2和3的小等差数列。

  用f[i][j]表示从i到j的字段能否全部消除,能全部消除的情况总共有3种模式

  [#####][#####]

  O[#####]O

  O[#####]O[#####]O

  其他都可以用这三种形式表示出来。

  dp[i]表示从1到i最多消去的个数。dp[i] = max(dp[i],dp[j - 1] + i - j + 1)

  错的原因:①在转移前,dp[i]的值应先设为dp[i-1],因为第i个数字可能并不在任何一个等差数列中。②二维数组f[i][j]写成了f[i,j],编译器不会报错,因为i,j也是个表达式,二维数组用一维的下标访问也没有问题,但算出来的结果肯定不对了。③使用位运算的时候要注意加括号,比如x&1==0,如果x<0,结果就会出错。感觉原因是这样的:-x&1==0,程序先判断了(1==0)得到一个false,再由这个false去&前面的-x。所以应该写成(x&1)==0。

技术分享
#include <stdio.h>#include <string.h>#include <map>std::map<long long, bool> mp;long long a[305], d;int dp[305];bool f[305][305];int main() {    int n, m, t;    scanf("%d", &t);    while (t--) {        scanf("%d%d", &n, &m);        for (int i = 1; i <= n; i++) {            scanf("%lld", &a[i]);        }        mp.clear();        for (int i = 1; i <= m; i++) {            scanf("%lld", &d);            mp[d] = true;        }        memset(f, false, sizeof(f));        for (int i = 1; i <= n; i++) {            f[i][i - 1] = true;        }        for (int j = 2; j <= n; j++) {            for (int i = 1; i + j - 1 <= n; i++) {                for (int k = i + 1; k < i + j - 1; k++) {                    if (f[i][k] && f[k + 1][i + j - 1]) {                        f[i][i + j - 1] = true;                    }                }                if (mp[a[i + j - 1] - a[i]] && f[i + 1][i + j - 2]) {                    f[i][i + j - 1] = true;                }                if (((a[i + j - 1] - a[i]) & 1) == 0 && mp[(a[i + j - 1] - a[i]) >> 1]) {                    for (int k = i + 1; k < i + j - 1; k++) {                        if ((a[k] << 1) == (a[i] + a[i + j - 1]) && f[i + 1][k - 1] && f[k + 1][i + j - 2]) {                            f[i][i + j - 1] = true;                        }                    }                }            }        }        memset(dp, 0, sizeof(dp));        for (int i = 2; i <= n; i++) {            dp[i] = dp[i - 1];            for (int j = 1; j < i; j++) {                if (f[j][i] && dp[j - 1] + i - j + 1 > dp[i]) {                    dp[i] = dp[j - 1] + i - j + 1;                }            }        }        printf("%d\n", dp[n]);    }    return 0;}
View Code

BD String[HDU5694]

  解法肯定是b(r)-b(l-1),只要能写出来b(x)函数就行。观察他的字符串构造,中间有一个b,右边的串是左边翻转加回文构成的,回文不改变bd的数量,翻转使bd数量交换,所以左右两边b和d的数量加起来是相等的,中间多一个b。另外S(n)的长度为2*S(n-1)+1=2^n-1。所以当x=2^n-1时,直接得到b(x)=(x/2)+1。对于一般情况,找到x长度介于S(n)和S(n+1)之间的n。只要用S(n+1)里的b的数量减去从第x+1位到S(n+1)末尾中的b的数量即可,而这一部分与字符串的开头同样长度的部分的关系是db数量交换,可以递归求解。

技术分享
#include <stdio.h>#include <string.h>long long b(long long x) {    if (x == 0) {        return 0;    }    long long l = 1;    while (l < x) {        l = l * 2 + 1;    }    if (l == x) {        return l / 2 + 1;    }    return (l / 2 + 1) - (l - x - b(l - x));}int main() {    int t;    long long l, r;    scanf("%d", &t);    while (t--) {        scanf("%lld%lld", &l, &r);        printf("%lld\n", b(r) - b(l - 1));    }    return 0;}
View Code

Gym Class[HDU5695]

  拓扑排序,每次输出可行的同学中id最高的那个。

  错的原因:每个同学要等到所有嫌弃他的同学都过了之后才能变成可行的。

技术分享
#include <stdio.h>#include <string.h>#include <queue>std::priority_queue<int> q;int f[100005];int M;int head[100005];struct EDGE {    int v, nex;} edge[100005];void addEdge(int a, int b) {    edge[M].v = b;    edge[M].nex = head[a];    head[a] = M++;}int main() {    int n, m, t, a, b;    scanf("%d", &t);    while (t--) {        scanf("%d%d", &n, &m);        memset(f, 0, sizeof(f));        M = 0;        memset(head, -1, sizeof(head));        for (int i = 1; i <= m; i++) {            scanf("%d%d", &a, &b);            addEdge(a, b);            f[b]++;        }        while (!q.empty()) {            q.pop();        }        for (int i = 1; i <= n; i++) {            if (f[i] == 0) {                q.push(i);            }        }        long long ans = 0;        int min = 0x7FFFFFFF;        while (!q.empty()) {            int x = q.top();            q.pop();            if (x < min) {                min = x;            }            ans += min;            for (int e = head[x]; e != -1; e = edge[e].nex) {                f[edge[e].v]--;                if (f[edge[e].v] == 0) {                    q.push(edge[e].v);                }            }        }        printf("%lld\n", ans);    }    return 0;}
View Code

 

2016"百度之星" - 初赛(Astar Round2A)