2016 百度之星 初赛A

A:hdoj 5690 All X
打个表看了看,发现循环最大不超过k,因为k最大为10000,就先暴力找一下,最多找k次。我们边找边记录结果,若发现相同的就说明找到一个循环节,直接跳出即可。
AC代码:

#include <cstdio>
#include <cstring>
#include <cmath>
#include <map>
#include <set>
#include <iostream>
#include <algorithm>
#include <queue>
#include <string>
#include <stack>
#define CLR(a, b) memset(a, b, sizeof(a))
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
const int MAXN = 3 * 1e6 + 10;
const int MOD = 9973;
const int INF = 0x3f3f3f3f;
LL ans[100000 + 1];
int main()
{
    int t, kcase = 1; scanf("%d", &t);
    while(t--) {
        LL x, m, k, c; scanf("%I64d%I64d%I64d%I64d", &x, &m, &k, &c);
        //printf("%d\n", Solve(x, k, m));
        LL top = 1, sum = x % k, l = 1, r = 1;
        ans[1] = sum;
        for(;;) {
            sum = (sum * 10 + x) % k;
            bool flag = false;
            for(int i = 1; i <= top; i++) {
                if(sum == ans[i]) {
                    l = i;
                    flag = true;
                    break;
                }
            }
            if(flag) break;
            ans[++top] = sum;
            if(top >= m) {
                break;
            }
        }
        bool flag;
        if(top >= m) {
            flag = (ans[m] == c);
        }
        else {
            r = top; m -= l - 1; m %= (r - l + 1);
            if(m == 0) m = r - l + 1;
            flag = (ans[l + m - 1] == c);
        }
        printf("Case #%d:\n", kcase++);
        printf(flag ? "Yes\n" : "No\n");
    }
    return 0;
}

B:hdoj 5691 Sitting in Line
状压dp
dp[i][j][s] 表示第i个位置选第j个人且已经就坐的人状态为s
没想到这都过了 (ˇˍˇ) 想~
AC代码:

#include <cstdio>
#include <cstring>
#include <cmath>
#include <map>
#include <set>
#include <iostream>
#include <algorithm>
#include <queue>
#include <string>
#include <stack>
#define CLR(a, b) memset(a, b, sizeof(a))
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
const int MAXN = 1e5 + 10;
const int MOD = 9973;
const int INF = -2 * 1e9;
int dp[18][18][1<<18];
int vis[18];
int b[18], a[18], p[18];
int main()
{
    for(int i = 0; i <= 17; i++) {
        b[i] = (1<<i);
    }
    int t, kcase = 1; scanf("%d", &t);
    while(t--) {
        int N; scanf("%d", &N);
        for(int i = 0; i < N; i++) vis[i] = -1;
        for(int i = 0; i < N; i++) {
            scanf("%d%d", &a[i], &p[i]);
            if(p[i] != -1) vis[p[i]] = i;
        }
        for(int i = 0; i < N; i++) {
            for(int j = 0; j < N; j++) {
                for(int s = 0; s < b[N]; s++) {
                    dp[i][j][s] = INF;
                }
            }
        }
        if(vis[0] == -1) {
            for(int i = 0; i < N; i++) {
                if(p[i] != -1) continue;
                dp[0][i][b[i]] = 0;
            }
        }
        else dp[0][vis[0]][b[vis[0]]] = 0;

        for(int i = 0; i < N-1; i++) {
            for(int j = 0; j < N; j++) {
                for(int s = 0; s < b[N]; s++) {
                    if(dp[i][j][s] == INF) continue;
                    if(vis[i+1] != -1) {
                        if(!(s & b[vis[i+1]])) {
                            int ns = s | b[vis[i+1]];
                            dp[i+1][vis[i+1]][ns] = max(dp[i+1][vis[i+1]][ns], dp[i][j][s] + a[j] * a[vis[i+1]]);
                        }
                        continue;
                    }

                    for(int k = 0; k < N; k++) {
                        if(p[k] != -1) continue;
                        if(!(s & b[k])) {
                            int ns = s | b[k];
                            dp[i+1][k][ns] = max(dp[i+1][k][ns], dp[i][j][s] + a[j] * a[k]);
                        }
                    }
                }
            }
        }
        int ans = INF;
        for(int i = 0; i < N; i++) {
            ans = max(ans, dp[N-1][i][b[N]-1]);
        }
        printf("Case #%d:\n", kcase++);
        printf("%d\n", ans);
    }
    return 0;
}

C:hdoj 5692 Snacks
第一眼感觉是树链剖分,后来发现一直从0节点出发,就是裸的DFS + 线段树区间更新。时间真的不够用了。。。

AC代码:

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <cstdio>
#include <cstring>
#include <cmath>
#include <map>
#include <set>
#include <iostream>
#include <algorithm>
#include <queue>
#include <string>
#include <stack>
#define CLR(a, b) memset(a, b, sizeof(a))
#define ll o<<1
#define rr o<<1|1
using namespace std;
typedef __int64 LL;
typedef pair<int, int> pii;
const int MAXN = 1e5 + 10;
const int MOD = 9973;
const int INF = 0x3f3f3f3f;
struct Tree {
    int l, r, len;
    LL lazy, Max;
};
Tree tree[MAXN<<2];
LL sval[MAXN];
LL val[MAXN];
int vs[MAXN], node[MAXN], dfs_clock;
int num[MAXN];
void PushUp(int o) {
    tree[o].Max = max(tree[ll].Max, tree[rr].Max);
}
void PushDown(int o) {
    if(tree[o].lazy) {
        tree[ll].lazy += tree[o].lazy;
        tree[rr].lazy += tree[o].lazy;
        tree[ll].Max += tree[o].lazy;
        tree[rr].Max += tree[o].lazy;
        tree[o].lazy = 0;
    }
}
void Build(int o, int l, int r) {
    tree[o].l = l; tree[o].r = r;
    tree[o].len = r - l + 1; tree[o].lazy = 0;
    if(l == r) {
        tree[o].Max = sval[node[l]];
        return ;
    }
    int mid = (l + r) >> 1;
    Build(ll, l, mid); Build(rr, mid+1, r);
    PushUp(o);
}
void Update(int o, int L, int R, LL v) {
    if(tree[o].l == L && tree[o].r == R) {
        tree[o].lazy += v;
        tree[o].Max += v;
        return ;
    }
    PushDown(o);
    int mid = (tree[o].l + tree[o].r) >> 1;
    if(R <= mid) Update(ll, L, R, v);
    else if(L > mid) Update(rr, L, R, v);
    else {
        Update(ll, L, mid, v);
        Update(rr, mid+1, R, v);
    }
    PushUp(o);
}
LL Query(int o, int L, int R) {
    if(tree[o].l == L && tree[o].r == R) {
        return tree[o].Max;
    }
    PushDown(o);
    int mid = (tree[o].l + tree[o].r) >> 1;
    if(R <= mid) return Query(ll, L, R);
    else if(L > mid) return Query(rr, L, R);
    else return max(Query(ll, L, mid), Query(rr, mid+1, R));
}
struct Edge {
    int from, to, next;
};
Edge edge[MAXN * 2];
int head[MAXN], edgenum;
void init() { edgenum = 0; CLR(head, -1); }
void addEdge(int u, int v) {
    Edge E = {u, v, head[u]};
    edge[edgenum] = E;
    head[u] = edgenum++;
}
void DFS(int u, int fa) {
    if(vs[u] == -1) {
        vs[u] = ++dfs_clock;
        node[dfs_clock] = u;
    }
    num[u] = 1;
    if(fa != -1) sval[u] = val[u] + sval[fa];
    else sval[u] = val[u];
    for(int i = head[u]; i != -1; i = edge[i].next) {
        int v = edge[i].to;
        if(v == fa) continue;
        DFS(v, u);
        num[u] += num[v];
    }
}
int main()
{
    int t, kcase = 1; scanf("%d", &t);
    while(t--) {
        int N, Q; scanf("%d%d", &N, &Q); init();
        for(int i = 0; i < N-1; i++) {
            int u, v; scanf("%d%d", &u, &v);
            addEdge(u, v); addEdge(v, u);
        }
        for(int i = 0; i < N; i++) scanf("%I64d", &val[i]), vs[i] = -1;
        dfs_clock = 0; DFS(0, -1); Build(1, 1, N);
        printf("Case #%d:\n", kcase++);
        while(Q--) {
            int op, x; LL y;
            scanf("%d", &op);
            if(op == 0) {
                scanf("%d%I64d", &x, &y);
                Update(1, vs[x], vs[x] + num[x] - 1, y - val[x]);
                val[x] = y;
            }
            else {
                scanf("%d", &x);
                //cout << vs[x] << ' ' << vs[x] + num[x] - 1 << endl;
                printf("%I64d\n", Query(1, vs[x], vs[x] + num[x] - 1));
            }
        }
    }
    return 0;
}

D:hdoj 5693 D Game
这个嘛,我估计补不了。(还是太SB)

E:hdoj 5694 BD String
f[i] 表示第 i 段的长度,fb[i]表示第 i 段中b的个数,同理 fd[i]
发现有这样的规律: ansb[i] 统计前 i 位的b的个数,同理 ansd[i]
ansb[n]=ansb[s]+(ansd[f[s]]ansd[f[s](nf[s]1)])+flag
flag 对应的是当前要统计的信息,因为存在字符的翻转。最大的 s 满足f[s]<n
flag==true 统计字符 b ,反之统计字符d
AC代码:

#include <cstdio>
#include <cstring>
#include <cmath>
#include <map>
#include <set>
#include <iostream>
#include <algorithm>
#include <queue>
#include <string>
#include <stack>
#define CLR(a, b) memset(a, b, sizeof(a))
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
const int MAXN = 1e5 + 10;
const int MOD = 9973;
const int INF = -2 * 1e9;
LL f[70], fb[70], fd[70];
LL DFS(LL n, bool flag) {
    if(n == 0) return 0;
    if(n == 1) return flag;
    int s;
    for(int i = 1; i <= 60; i++) {
        if(f[i] == n) {
            return flag ? fb[i] : fd[i];
        }
        if(f[i] > n) {
            s = i - 1; break;
        }
    }
    LL sum = flag ? fb[s] : fd[s];
    LL R = f[s], L = R - (n - f[s] - 1) + 1;
    //cout << n << ' ' << L << ' ' << R << endl;
    return sum + DFS(R, !flag) - DFS(L - 1, !flag) + flag;
}
int main()
{
    f[1] = 1; fd[1] = 0; fb[1] = 1;
    for(int i = 2; i <= 60; i++) {
        f[i] = f[i-1] * 2 + 1;
        fb[i] = fb[i-1] + 1 + fd[i-1];
        fd[i] = fb[i-1] + fd[i-1];
        //cout << f[i] << ' ' << i << endl;
    }
    int t, kcase = 1; scanf("%d", &t);
    while(t--) {
        LL L, R; scanf("%I64d%I64d", &L, &R);
        printf("%I64d\n", DFS(R, 1) - DFS(L-1, 1));
    }
    return 0;
}

F:hdoj 5695 Gym Class
建个有向图,然后就是维护一个最大堆的拓扑序。
半小时才去看。真是SB中的SB。

AC代码:

#include <cstdio>
#include <cstring>
#include <cmath>
#include <map>
#include <set>
#include <iostream>
#include <algorithm>
#include <queue>
#include <string>
#include <stack>
#define CLR(a, b) memset(a, b, sizeof(a))
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
const int MAXN = 1e5 + 10;
const int MOD = 9973;
const int INF = 0x3f3f3f3f;
vector<int> G[MAXN];
int in[MAXN];
int main()
{
    int t; scanf("%d", &t);
    while(t--) {
        int n, m; scanf("%d%d", &n, &m);
        for(int i = 1; i <= n; i++) G[i].clear(), in[i] = 0;
        for(int i = 1; i <= m; i++) {
            int u, v; scanf("%d%d", &u, &v);
            G[u].push_back(v); in[v]++;
        }
        priority_queue<int, vector<int>, less<int> > Q;
        for(int i = 1; i <= n; i++) {
            if(in[i] == 0) {
                Q.push(i);
            }
        }
        LL ans = 0;
        int Min = n + 1;
        while(!Q.empty()) {
            int u = Q.top(); Q.pop();
            Min = min(Min, u);
            ans += Min;
            for(int i = 0; i < G[u].size(); i++) {
                int v = G[u][i];
                if(--in[v] == 0) {
                    Q.push(v);
                }
            }
        }
        printf("%I64d\n", ans);
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值