JSOI2016

A 最佳团体

题面:Luogu
题解:分数规划+树形背包
\(dp[u][j]\)表示根为u,选了k个人(加上自己)的最大值
转移很简单,判断直接看是否\(dp[1][k]>=0\)就可以了
注意这道题卡常,我把eps调到了1e-4,上界调到了1e2才过(然而可以卡掉),还把双向边去掉了
codeA

B 独特的树叶

题面:Luogu
题解:树hash
树hash感觉好奇怪啊
一种是取模,另一种是异或,都是由转移方程推出来的(取模不能换根,异或可以)
另外你base取得不同有时候也会出现一些奇怪的问题
这道题就是先把A给Hash掉,把所有值扔到set里(map,unordered_map应该也行)
然后枚举B的树叶,求以这片叶子的儿子的Hash值,然后看set里有没有,有的话就输出
codeB

C 扭动的回文串

题面:Luogu
题解:manacher+hash
显然前两种情况跑一下manacher即可
第三种情况必定是两端对称加上中间一段回文(全部可以为空),比如\(BC\ E\ CB\)
所以二分两端对称半径即可
codeC

D 灯塔

题面:Luogu
题解:st表
我们要对每个i求出
\[\max\left\{a_j+\left\lceil\sqrt{|i-j|}\right\rceil\right\}-a_i\]
\(\sqrt{|i-j|}\)只有\(\sqrt n\)种,直接枚举,用st表求出最大值
复杂度:\(O(n\sqrt n)\)
还有一种用决策单调性+分治/单调队列的,复杂度\(O(n\log n)\) 咕咕咕
codeD

codeA

#include<bits/stdc++.h>
using namespace std;
inline void read(int& x)
{
    x = 0; char c = getchar();
    while (!isdigit(c)) c = getchar();
    while (isdigit(c)) x = x * 10 + c - '0', c = getchar();
}
#define maxn 2505
#define eps 1e-4
struct Edge
{
    int fr, to;
}eg[maxn << 1];
int head[maxn], edgenum;
inline void add(int fr, int to)
{
    eg[++edgenum] = { head[fr],to };
    head[fr] = edgenum;
}
double l, r, mid, dp[maxn][maxn], v[maxn];
int K, n, cost[maxn], val[maxn], siz[maxn];

void dfs(int rt, int fa)
{
    dp[rt][0] = 0, dp[rt][1] = v[rt], siz[rt] = 1;
    for (int i = head[rt]; i; i = eg[i].fr)
    {
        //if (eg[i].to == fa) continue;
        dfs(eg[i].to, rt);
        for (int j = siz[rt]; j; --j)
            for (int k = 0; k <= siz[eg[i].to]; ++k)
                dp[rt][j + k] = max(dp[rt][j + k], dp[rt][j] + dp[eg[i].to][k]);
        siz[rt] += siz[eg[i].to];
    }
}
bool check()
{
    for (int i = 2; i <= n; ++i) v[i] = val[i] - cost[i] * mid;
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= K; ++j)
            dp[i][j] = -1e9;
    dfs(1, 0);
    return dp[1][K] >= 0;
}
int main()
{
    read(K), read(n), ++n, ++K;
    for (int i = 2, tp; i <= n; ++i)
        read(cost[i]), read(val[i]), read(tp), ++tp, add(tp, i);//add(i,tp);
    l = 0, r = 1e2;
    while (r - l > eps)
    {
        mid = (l + r) / 2;
        if (check()) l = mid;
        else r = mid;
    }
    printf("%.3lf\n", l);
    return 0;
}

top

codeB

#include<bits/stdc++.h>
using namespace std;
inline void read(int& x)
{
    x = 0; char c = getchar();
    while (!isdigit(c)) c = getchar();
    while (isdigit(c)) x = x * 10 + c - '0', c = getchar();
}
#define ull unsigned long long
const ull base=1e9+7;
#define maxn 100005
set<ull> s;
struct Graph
{
    struct Edge
    {
        int fr, to;
    }eg[maxn << 1];
    int head[maxn], edgenum, num;
    int siz[maxn], deg[maxn];
    ull val[maxn], Hash[maxn];
    inline void add(int fr, int to)
    {
        eg[++edgenum] = { head[fr],to };
        head[fr] = edgenum; ++deg[to];
    }
    inline void init()
    {
        int x, y;
        for (int i = 1; i < num; ++i) read(x), read(y), add(x, y), add(y, x);
    }
#define to eg[i].to
    void dfs_gethash(int rt, int fa)
    {
        siz[rt] = 1; val[rt] = 1;
        for (int i = head[rt]; i; i = eg[i].fr)
        {
            if (to == fa) continue;
            dfs_gethash(to, rt);
            siz[rt] += siz[to];
            val[rt] ^= val[to] * base + siz[to];
        }
    }
    void dfs_changeroot(int rt, int fa)
    {
        Hash[rt] = fa ? val[rt] ^ ((Hash[fa] ^ (val[rt] * base + siz[rt])) * base + num - siz[rt]) : val[rt];
        for (int i = head[rt]; i; i = eg[i].fr)
            if (to != fa) dfs_changeroot(to, rt);
    }
    inline bool isleaf(int rt)
    {
        return deg[rt] == 1;
    }
#undef to
    inline bool check(int rt)
    {
        return s.count(Hash[eg[head[rt]].to] ^ (val[rt] * base + 1));
    }
}A, B;
int n;
int main()
{
    //freopen("test.in", "r", stdin);
    read(n);
    A.num = n, B.num = n + 1;
    A.init(), B.init();
    A.dfs_gethash(1, 0); A.dfs_changeroot(1, 0);
    for (int i = 1; i <= A.num; ++i) s.insert(A.Hash[i]);
    for (int i = 1; i <= B.num; ++i)
        if (!B.isleaf(i))
        {
            B.dfs_gethash(i, 0);
            B.dfs_changeroot(i, 0);
            break;
        }
    for (int i = 1; i <= B.num; ++i)
        if (B.isleaf(i) && B.check(i))
        {
            printf("%d\n", i);
            break;
        }
    return 0;
}

top

codeC

#include<bits/stdc++.h>
using namespace std;
#define maxn 200005
#define base 131
#define ull unsigned long long
struct str
{
    char s[maxn];
    int len, p[maxn];
    void Gets()
    {
        char c = getchar();
        s[0] = '~', s[len = 1] = '#';
        while (!isalpha(c)) c = getchar();
        while (isalpha(c)) s[++len] = c, s[++len] = '#', c = getchar();
    }
    void manacher()
    {
        for (int i = 1, r = 0, mid = 0; i <= len; ++i)
        {
            if (i <= r) p[i] = min(p[(mid << 1) - i], r - i + 1);
            while (s[i - p[i]] == s[i + p[i]]) ++p[i];
            if (p[i] + i > r) r = p[i] + i - 1, mid = i;
        }
    }
    void init()
    {
        Gets();
        manacher();
    }
}A, B;
int ans, n;
ull Hasha[maxn], Hashb[maxn], Pow[maxn];
inline bool check(int l1, int r1, int l2, int r2)
{
    int len = r1 - l1 + 1;
    ull x = Hasha[r1] - Hasha[l1 - 1] * Pow[len];
    ull y = Hashb[l2] - Hashb[r2 + 1] * Pow[len];
    return x == y;
}
inline int solve(int L, int R)
{
    int l = 0, r = min(L, n - R + 1), mid, ans = 0;
    while (l <= r)
    {
        mid = (l + r) >> 1;
        if (check(L - mid + 1, L, R, R + mid - 1)) l = mid + 1, ans = mid;
        else r = mid - 1;
    }
    return ans;
}
int main()
{
    scanf("%d", &n);
    A.init(); B.init();
    for (int i = 1; i <= A.len; ++i) --A.p[i], --B.p[i];
    Pow[0] = 1;
    for (int i = 1; i <= n; ++i)
    {
        ans = max(ans, max(A.p[i], B.p[i]));
        Pow[i] = Pow[i - 1] * base;
    }
    for (int i = 2; i <= A.len; i += 2) Hasha[i >> 1] = Hasha[(i >> 1) - 1] * base + A.s[i];
    for (int i = B.len - 1; i > 1; i -= 2) Hashb[i >> 1] = Hashb[(i >> 1) + 1] * base + B.s[i];
    int l, r;
    for (int i = 2; i < A.len; ++i)
    {
        l = (i - A.p[i] + 1) >> 1, r = (i + A.p[i]) >> 1;
        ans = max(ans, A.p[i] + solve(l - 1, r) * 2);
    }
    for (int i = 2; i < B.len; ++i)
    {
        l = (i - B.p[i] + 1) >> 1, r = (i + B.p[i]) >> 1;
        ans = max(ans, B.p[i] + solve(l, r + 1) * 2);
    }
    printf("%d\n", ans);
    return 0;
}

top

codeD

#include<bits/stdc++.h>
using namespace std;
inline void read(int& x)
{
    x = 0; char c = getchar();
    while (!isdigit(c)) c = getchar();
    while (isdigit(c)) x = x * 10 + c - '0', c = getchar();
}
#define maxn 500005
int lg[maxn], st[maxn][21], h[maxn], n;
inline int getans(int l, int r)
{
    int tp = lg[r - l + 1];
    return max(st[l][tp], st[r - (1 << tp) + 1][tp]);
}
inline void st_init()
{
    for (int i = 2; i <= n; ++i) lg[i] = lg[i >> 1] + 1;
    for (int i = 1; i <= n; ++i) st[i][0] = h[i];
    for (int i = 1; i <= 19; ++i)
        for (int j = 1; j + (1 << i) - 1 <= n; ++j)
            st[j][i] = max(st[j][i - 1], st[j + (1 << (i - 1))][i - 1]);
}
int main()
{
    read(n);
    for (int i = 1; i <= n; ++i) read(h[i]);
    st_init();
    for (int i = 1; i <= n; ++i)
    {
        int ans = 0;
        for (int j = 1;; ++j)
        {
            int l = (j - 1) * (j - 1) + 1, r = j * j;
            if (i + l <= n) ans = max(ans, getans(i + l, min(n, i + r)) + j - h[i]);
            if (i - l >= 1) ans = max(ans, getans(max(1, i - r), i - l) + j - h[i]);
            if (i - r <= 1 && i + r >= n) break;
        }
        printf("%d\n", ans);
    }
    return 0;
}

top

猜你喜欢

转载自www.cnblogs.com/123789456ye/p/12386593.html