其他分享
首页 > 其他分享> > XJOI划水划水

XJOI划水划水

作者:互联网

待家里感觉没啥事可做, 趁着开学还有两天, 成功鸽掉了数学课, 来学车OJ学车

感觉 IOI 赛制挺海星, 见到了一些神奇的学校

嗯, 听说第一题难度挺适合, 于是发现果然是一道神奇的开车题, 然后手玩了一下, 交了两发, 稳定过 n = 2 的点, 感觉这是真 · 入门难度啊

于是决定弃疗做 T2, 有些 trivial, 看了三遍题意终于理解样例在干什么了... 赶紧写写写, 套了个最长链的板子成功过了

看 T3, 咋又来期望啊, 感觉有点慌, 于是果断 skip, 发现 T4 998244353, 答案还是卷积形式??? 感觉 1e15的数据像是什么神奇筛法的复杂度...扔了看T5, 看着那题面就知道又是什么大码力数据结构, 想起了 uoj 上某集训队胡策中的神仙题, 决定滚回去看 T1

emm... 又瞪了一会儿 T1, 发现 T1 没看到最外层路有方向??? 又重新构造了一个新的方案, 交了两发, 发现自己没输出路径长度233, 慌忙改了过来

发现 rank 榜上一堆 T4 切了的人啊... 于是又去想了会儿 T4, 发现 69分 分个块后非常sb, 写了以后又卡卡预处理优化了一下, 成功卡上了95分(比赛结束才发现循环展开有卡到 100的???)

T3挺鸽的, 那个60几分dp应该很显然, 然而 WA 到自闭, 赛后发现 wi, vi 成功看反233

以下是口胡的题解:

T1: 随便乱搞, 网友们好像人均一个做法

T2: 每个点维护个最长链长度, 并算出与权值乘积即可, 显然能证明这是对的

T3: dp 是 \(O(n^2m)\) 的, 然后你可以把操作用背包合并一下, 每次强制取到几个不同区间就可以了, 复杂度是 \(O(nm)\)

T4: 就说一个卡常做法吧, 求前缀和时推个公式可以一个log求出来, 然后就可以数论分块做到 \(O(\sqrt n \log n)\) , 正解不带 log, 不过这种方法用预处理搞一搞加一个卡常还是可以过的

T5: 貌似可以树套树维护凸包??? 然而写不出来.... 就挖个坑在这好了

继续贯彻放个代码就跑原则:

T1

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
template <typename T> inline void read(T &FF) {
    int RR = 1; FF = 0; char CH = getchar();
    for(; !isdigit(CH); CH = getchar()) if(CH == '-') RR = -RR;
    for(; isdigit(CH); CH = getchar()) FF = FF * 10 + CH - 48;
    FF *= RR;
}
inline void file(string str) {
    freopen((str + ".in").c_str(), "r", stdin);
    freopen((str + ".out").c_str(), "w", stdout);
}
int main() {
    //file("");
    int n;
    read(n);
    cout << n * (n + 1) - 1 << endl;
        if(n & 1) {
            for(int i = 1; i < n; i += 2) {
                for(int j = n + 1; j >= 1; j--)
                    if(j & 1) cout << i + 1 << " " << j << endl;
                    else cout << i << " " << j << endl;
                for(int j = 1; j <= n + 1; j++)
                    if(j & 1) cout << i << " " << j << endl;
                    else cout << i + 1 << " " << j << endl;
            }
            for(int i = n + 1; i >= 1; i--)
                cout << n << " " << i << endl;
        }
        else {
            for(int i = 1; i < n + 1; i += 2) {
                for(int j = 1; j <= n; j++)
                    if(j & 1) cout << j << " " << i << endl;
                    else cout << j << " " << i + 1 << endl;
                for(int j = n; j >= 1; j--)
                    if(j & 1) cout << j << " " << i + 1 << endl;
                    else cout << j << " " << i << endl;
            }
            for(int i = 1; i <= n; i++)
                cout << i << " " << n + 1 << endl;
        }
    return 0;
}

T2

#include <bits/stdc++.h>
using namespace std;
template <typename T> inline void read(T &FF) {
    int RR = 1; FF = 0; char CH = getchar();
    for(; !isdigit(CH); CH = getchar()) if(CH == '-') RR = -RR;
    for(; isdigit(CH); CH = getchar()) FF = FF * 10 + CH - 48;
    FF *= RR;
}
const int MAXN = 50000 + 10;
int f[MAXN], wi[MAXN];
struct edge{
    int to, nxt, w;
}edges[MAXN*2];
int tot;
int head[MAXN];
void add_edge(int u,int v,int w){
    edges[tot].to = v;
    edges[tot].w = w;
    edges[tot].nxt = head[u];
    head[u] = tot++;
}
int dist[MAXN][3];
int longest[MAXN];
int dfs1(int u,int fa){
    if(dist[u][0] >= 0) return dist[u][0];
    dist[u][0] = dist[u][1] = dist[u][2] = longest[u] = 0;

    for(int e = head[u]; e != -1; e = edges[e].nxt){
        int v = edges[e].to;
        if(v == fa) continue;

        if(dist[u][0] < dfs1(v,u) + edges[e].w){
            longest[u] = v;
            dist[u][1] = max(dist[u][1],dist[u][0]);
            dist[u][0] = dfs1(v,u) + edges[e].w;
        }
        else if(dist[u][1] < dfs1(v,u) + edges[e].w)
            dist[u][1] = max(dist[u][1],dfs1(v,u) + edges[e].w);
    }
    return dist[u][0];
}

void dfs2(int u,int fa){
    for(int e = head[u]; e != -1; e = edges[e].nxt){
        int v = edges[e].to;
        if(v == fa) continue;
        if(v == longest[u]) dist[v][2] = max(dist[u][2],dist[u][1]) + edges[e].w;
        else dist[v][2] = max(dist[u][2],dist[u][0]) + edges[e].w;
        dfs2(v,u);
    }
}
int main() {
    int n, res = 0;
    read(n);
    memset(dist,-1,sizeof(dist));
    memset(head,-1,sizeof(head));
    memset(longest,-1,sizeof(longest));
    for(int i = 1; i <= n; i++)
        read(wi[i]);
    for(int i = 2; i <= n; i++){
        int u, v;
        read(u), read(v);
        add_edge(u, v, 1);
        add_edge(v, u, 1);
    }
    dfs1(1,-1), dfs2(1,-1);
    for(int i = 1; i <= n; i++)
        res = max(wi[i] * max(dist[i][0], dist[i][2]), res);
    cout << res << endl;
    return 0;
}

T3

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
template <typename T> inline void read(T &FF) {
    int RR = 1; FF = 0; char CH = getchar();
    for(; !isdigit(CH); CH = getchar()) if(CH == '-') RR = -RR;
    for(; isdigit(CH); CH = getchar()) FF = FF * 10 + CH - 48;
    FF *= RR;
}
inline void file(string str) {
    freopen((str + ".in").c_str(), "r", stdin);
    freopen((str + ".out").c_str(), "w", stdout);
}
#define int long long
const int N = 2010;
int n, m, op[N], f[N][2], p[N], g[N], pre[N], succ[N], sum[N];
int work(int l, int r) {
    if(r <= p[1]) return 0;
    int ll = succ[l], rr = pre[r];
    if(ll > rr) return INT_MAX;
    return (sum[rr] - sum[ll]) + f[l][1] + f[r][0];
}
int solve(int l, int r) {
    if(r <= p[1]) return 0;
    int res = INT_MAX;
    for(int i = 1; i <= l - 1; i++)
        res = min(res, work(l - i, r - i) + (r - l + 1) * g[i]);
    return res;
}
signed main() {
    //file("");
    int T;
    read(T);
    while(T--) {
        read(n), read(m);
        for(int i = 1; i <= n; i++) {
            read(p[i]);
            for(int j = p[i - 1] + 1; j <= p[i]; j++)
                pre[j] = i - 1, succ[j] = i;
        }
        int vi, wi;
        for(int i = 1; i <= p[n]; i++) g[i] = INT_MAX;
        for(int i = 1; i <= m; i++) {
            read(wi), read(vi);
            for(int j = vi; j <= p[n]; j++)
                g[j] = min(g[j], g[j - vi] + wi);
        }
        for(int i = 1; i <= n; i++) {
            for(int j = p[i - 1] + 1; j <= p[i]; j++)
                f[j][0] = solve(p[i - 1] + 1, j);
            for(int j = p[i]; j >= p[i - 1] + 1; j--)
                f[j][1] = solve(j, p[i]);
            sum[i] = sum[i - 1] + f[p[i]][0];
        }
        cout << (sum[n] >= INT_MAX ? -1 : sum[n]) << endl;
    }
    return 0;
}

T4

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
template <typename T> inline void read(T &FF) {
    int RR = 1; FF = 0; char CH = getchar();
    for(; !isdigit(CH); CH = getchar()) if(CH == '-') RR = -RR;
    for(; isdigit(CH); CH = getchar()) FF = FF * 10 + CH - 48;
    FF *= RR;
}
inline void file(string str) {
    freopen((str + ".in").c_str(), "r", stdin);
    freopen((str + ".out").c_str(), "w", stdout);
}
#define mod 998244353
int pre[20000010];
LL get_res(LL x) {
    if(x == 0) return 0;
    if(x <= 20000000 && pre[x] != -1) return pre[x];
    if(x <= 2) return x == 1 ? 1 : 3;
    LL res = (2 * get_res(x / 2) % mod + x / 2) % mod;
    res = x & 1 ? (res + 1) % mod : res;
    if(x <= 20000000) pre[x] = res;
    return res;
}
LL sum(LL l, LL r) {
    return (get_res(r) - get_res(l - 1) + mod) % mod;
}
LL get_ans(LL x) {
    LL res = 0;
    for(LL i = 1; i <= x; i++) {
        LL j = x / (x / i);
        res = (res + sum(i, j) * (x / i) % mod) % mod;
        i = j;
    }
    return res;
}
int main() {
    //file("");
    LL n;
    read(n);
    memset(pre, -1, sizeof(pre));
    for(int i = 1; i <= 20000000; i++)
        get_res(i);
    cout << get_ans(n) << endl;
    return 0;
}

标签:划水,CH,dist,XJOI,RR,int,str,FF
来源: https://www.cnblogs.com/magicduck/p/12641419.html