• 《2018 Multi-University Training Contest 10部分题解》


    折磨折磨折磨。

    Problem E. TeaTree:

    这题让我重新认识了dsu on tree,现在算是理解了dsu on tree的内核了,一开始做的时候已经在考虑可能是dsu on tree了。但是看了下通过率觉得应该是有技巧的。

    结果还真是dsu on tree。当然也可以线段树合并。

    这里最主要的一点,就是怎么处理gcd的问题。

    首先,1e5之内的数的因子最多只有100多个,所以我们可以暴力便利每个点的因子。

    然后判断子树中是否出现过这个因子。

    这里只有两种情况:根和子树,子树和另外一个子树。

    一开始写dsu on tree的时候,一直想边加入边统计答案,但是这样可能导致子树中的子树的答案更新到u上。

    所以后面想了下,搜一遍先统计答案,再搜一遍加入贡献就行了。

    注意的是,因为重儿子贡献没有删去,并且它不会再被solve统计,所以我们先判断重儿子和根的因子关系,然后再加入根的因子。

    然后再去先去统计当前已经合并到根里的因子和一棵子树的关系,然后再去加入一棵子树的贡献,这样就不会出现错误的情况。

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef pair<LL, int> pii;
    const int N = 1e5 + 5;
    const int M = 2000 + 5;
    const LL Mod = 1e9 + 7;
    #define pi acos(-1)
    #define INF 1e18
    #define dbg(ax) cout << "now this num is " << ax << endl;
    namespace FASTIO {
        inline LL read() {
            LL x = 0, f = 1;
            char c = getchar();
            while (c < '0' || c > '9') {
                if (c == '-')
                    f = -1;
                c = getchar();
            }
            while (c >= '0' && c <= '9') {
                x = (x << 1) + (x << 3) + (c ^ 48);
                c = getchar();
            }
            return x * f;
        }
    }
    using namespace FASTIO;
    
    int n,val[N],sz[N],son[N],num[N],Son = 0,ans[N];
    vector<int> G[N],vec[N];
    void init() {
        for(int i = 1;i < N;++i) 
            for(int j = i;j < N;j += i) vec[j].push_back(i); 
    }
    void dfs(int u,int fa) {
        sz[u] = 1;
        for(auto v : G[u]) {
            if(v == fa) continue;
            dfs(v,u);
            sz[u] += sz[v];
            if(sz[v] > sz[son[u]]) son[u] = v;
        }
    }
    int solve(int u,int fa) {
        int mxx = -1;
        for(auto v : vec[val[u]]) {
            if(num[v] > 0) mxx = max(mxx,v);
        }
        for(auto v : G[u]) {
            if(v == fa || v == Son) continue;
            mxx = max(mxx,solve(v,u));
        }
        return mxx;
    }
    void add(int u,int fa) {
        for(auto v : vec[val[u]]) {
            num[v]++;
        }
        for(auto v : G[u]) {
            if(v == fa || v == Son) continue;
            add(v,u);
        }
    } 
    void del(int u,int fa) {
        for(auto v : vec[val[u]]) {
            num[v]--;
        }
        for(auto v : G[u]) {
            if(v == fa || v == Son) continue;
            del(v,u);
        }
    }
    void dfs1(int u,int fa,int opt) {
        for(auto v : G[u]) {
            if(v == fa || v == son[u]) continue;
            dfs1(v,u,0);
        }
        if(son[u] != 0) dfs1(son[u],u,1),Son = son[u];
        ans[u] = -1;
        for(auto v : vec[val[u]]) {
            if(num[v] > 0) ans[u] = max(ans[u],v);
            num[v]++;
        }
        for(auto v : G[u]) {
            if(v == fa || v == Son) continue;
            ans[u] = max(ans[u],solve(v,u));
            add(v,u);
        }
        Son = 0;
        if(opt == 0) del(u,fa);
    }
    int main() {
        memset(ans,-1,sizeof(ans));
        init();
        n = read();
        for(int i = 2;i <= n;++i) {
            int x;x = read();
            G[x].push_back(i);
            G[i].push_back(x);
        }
        for(int i = 1;i <= n;++i) val[i] = read();
        dfs(1,0);
        dfs1(1,0,0);
        for(int i = 1;i <= n;++i) printf("%d
    ",ans[i]);
       // system("pause");
        return 0;
    }
    /*
    10
    1 2 3 4 5 6 7 8 9
    2 4 6 8 2 4 1 5 6 8 
    
    */
    View Code

    Problem H. Pow:

    看了下样例,显然是2^n,然后高精度乘法就行了。

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef pair<LL, int> pii;
    const int N = 1e5 + 5;
    const int M = 2000 + 5;
    const LL Mod = 998244353;
    #define pi acos(-1)
    #define INF 1e18
    #define dbg(ax) cout << "now this num is " << ax << endl;
    namespace FASTIO {
    inline LL read() {
        LL x = 0, f = 1;
        char c = getchar();
    
        while (c < '0' || c > '9') {
            if (c == '-')
                f = -1;
    
            c = getchar();
        }
    
        while (c >= '0' && c <= '9') {
            x = (x << 1) + (x << 3) + (c ^ 48);
            c = getchar();
        }
    
        return x * f;
    }
    }
    using namespace FASTIO;
    
    int ans[N],len = 0;
    
    void mul() {
        int ma = 0;
        for(int i = 1;i <= len;++i) {
            int jw = (ans[i] * 2 + ma) / 10;
            ans[i] = (ans[i] * 2 + ma) % 10;
            ma = jw;
        }
        while(ma != 0) {
            ans[++len] = ma % 10;
            ma /= 10;
        }
    }
    int main() {
        int ca;ca = read();
        while(ca--) {
            memset(ans,0,sizeof(ans));
            int n;n = read();
            len = 1;
            ans[1] = 1;
            for(int i = 1;i <= n;++i) mul();
            for(int i = len;i >= 1;--i) printf("%d",ans[i]);
            printf("
    ");
        }
    
    
       // system("pause");
        return 0;
    }
    View Code

    Problem I. Count:

    也是非常有意思的一个题目。

    先打了个表:
    当i为质数时:贡献就是i / 2;

    当i不为质数时:

    当i为偶数时,那么假设gcd(i + j,i - j) = k

    那么可以猜测:i = xk,j = yk,i + j = (x + y) k ,i - j = (x - y) k

    所以,i的贡献就是1 ~ i - 1中与i互质的数。也就是$varphi (i)$

    当i为奇数时:

    如果j也为奇数,那么i + j,i - j都是偶数,最少也是2。

    所以贡献就是1 ~ i -1中的偶数且与i互质,看了下表,发现这个值= $frac{varphi (i)}{2}$

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef pair<LL, int> pii;
    const int N = 2e7 + 5;
    const int M = 2000 + 5;
    const LL Mod = 998244353;
    #define pi acos(-1)
    #define INF 1e18
    #define dbg(ax) cout << "now this num is " << ax << endl;
    namespace FASTIO {
    inline LL read() {
        LL x = 0, f = 1;
        char c = getchar();
    
        while (c < '0' || c > '9') {
            if (c == '-')
                f = -1;
    
            c = getchar();
        }
    
        while (c >= '0' && c <= '9') {
            x = (x << 1) + (x << 3) + (c ^ 48);
            c = getchar();
        }
    
        return x * f;
    }
    }
    using namespace FASTIO;
    
    int phi[N],prime[N],tot = 0;
    bool vis[N];
    LL ans[N];
    void init() {
        for(int i = 2;i < N;++i) {
            if(!vis[i]) {
                prime[++tot] = i;
                phi[i] = i - 1;
            }
            for(int j = 1;j <= tot && prime[j] * i < N;++j) {
                vis[i * prime[j]] = 1;
                if(i % prime[j] == 0) {
                    phi[i * prime[j]] = phi[i] * prime[j];
                    break;
                }
                else {
                    phi[i * prime[j]] = phi[i] * phi[prime[j]];
                }
            }
        }
        ans[1] = 0;
        for(int i = 2;i < N;++i) {
            ans[i] = ans[i - 1];
            if(!vis[i]) ans[i] += i / 2;
            else {
                if(i % 2 == 0) ans[i] += phi[i];
                else ans[i] += phi[i] / 2;
            }
        }
    
    }
    int main() {
        init();
        int ca;ca = read();
        while(ca--) {
            int n;n = read();
            /*for(int i = 1;i <= n;++i) {
                int ma = 0;
            //  printf("phi[%d] is %d sum[%d] is %d
    ",i,phi[i],i,sum[i]);
                for(int j = 1;j < i;++j) {
                    printf("%d %d gcd(%d,%d) is %d
    ",i,j,i + j,i - j,__gcd(i + j,i - j));
                }
            } */   
            printf("%lld
    ",ans[n]);
        }
    
        //system("pause");
        return 0;
    }
    View Code

    Problem J. CSGO:

    这题的思路很巧妙。

    因为是|x - y|那么对于每一对x,y去掉绝对值之后肯定只有两种状态x - y,-x + y。

    所以只需要状压所有状态(1 << k)即可。

    然后很显然的是如果主武器状态为s,那么服务器这一位的状态肯定是s ^ 1。(因为是去掉绝对值)

    最后加上最大的两个即可。

    这里很显然会存在一些不合法的状态,即无法产生的状态,但是这些状态加入是不会对答案产生影响的,因为答案肯定会合法的状态的最值  > 不合法的状态的最值

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef pair<LL, int> pii;
    const int N = 1e5 + 5;
    const int M = 2000 + 5;
    const LL Mod = 1e9 + 7;
    #define pi acos(-1)
    #define INF 1e18
    #define dbg(ax) cout << "now this num is " << ax << endl;
    namespace FASTIO {
        inline LL read() {
            LL x = 0, f = 1;
            char c = getchar();
            while (c < '0' || c > '9') {
                if (c == '-')
                    f = -1;
                c = getchar();
            }
            while (c >= '0' && c <= '9') {
                x = (x << 1) + (x << 3) + (c ^ 48);
                c = getchar();
            }
            return x * f;
        }
    }
    using namespace FASTIO;
    
    LL a[N],b[N],s[N],ss[N],mx[N][10],fx[N][10];
    int n,m,k;
    LL solve(int state) {//主武器状态
        for(int i = 1;i <= n;++i) {
            a[i] = s[i];
            for(int j = 1;j <= k;++j) {
                int g = (state >> (j - 1)) & 1;
                if(g == 0) {
                    a[i] -= mx[i][j];
                }
                else a[i] += mx[i][j];
            }
        }
        sort(a + 1,a + n + 1);
        for(int i = 1;i <= m;++i) {
            b[i] = ss[i];
            for(int j = 1;j <= k;++j) {
                int g = (state >> (j - 1)) & 1;
                if(g == 0) {
                    b[i] += fx[i][j];
                }
                else b[i] -= fx[i][j];
            }
        }
        sort(b + 1,b + m + 1);
        return a[n] + b[m];
    }
    int main() {
        int ca;ca = read();
        while(ca--) {
            n = read(),m = read(),k = read();
            for(int i = 1;i <= n;++i) {
                s[i] = read();
                for(int j = 1;j <= k;++j) mx[i][j] = read();
            }
            for(int i = 1;i <= m;++i) {
                ss[i] = read();
                for(int j = 1;j <= k;++j) fx[i][j] = read();
            }
            LL ans = 0;
            for(int i = 0;i < (1 << k);++i) {
                ans = max(ans,solve(i));
            }
            printf("%lld
    ",ans);
        }
    
        //system("pause");
        return 0;
    }
    View Code

    Problem L.Videos:

    好家伙,写题解的时候发现题意读错了。

    这题的题意是:

    多个人可以在重叠的时间段看不同的video。

    做的时候一直以为一个时间内只能放一部video。

    看到的第一眼就觉得是费用流,结果建图一直建不对。

    一直纠结于对时间拆点。

    其实这里不需要对时间进行拆点。

    建图思路:

    首先很显然video之间可以建立边,注意计算一直费用即可。

    直接每个video向汇点连容量为1的点。

    然后时间点的限制就用来video之间连边。

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef pair<int, int> pii;
    const int N = 1e3 + 5;
    const int M = 1e4 + 5;
    const LL Mod = 998244353;
    #define pi acos(-1)
    #define INF 1e9
    #define dbg(ax) cout << "now this num is " << ax << endl;
    namespace FASTIO {
    inline LL read() {
        LL x = 0, f = 1;
        char c = getchar();
    
        while (c < '0' || c > '9') {
            if (c == '-')
                f = -1;
    
            c = getchar();
        }
    
        while (c >= '0' && c <= '9') {
            x = (x << 1) + (x << 3) + (c ^ 48);
            c = getchar();
        }
    
        return x * f;
    }
    }
    using namespace FASTIO;
    
    int n,m,s,t,cnt = -1,maxflow = 0,mincost = 0;
    int head[N],pre[N],cal[N],dis[N],vis[N];//pre记录前驱,cal记录最短增广路上的最小流量,dis记录最短路
    struct Node{int to,dis,flow,next;}e[M<<1];
    int u[N],v[N],w[N],op[N];
    inline void add(int u,int v,int w,int flow)//费用,容量
    {
        e[++cnt].to = v,e[cnt].dis = w,e[cnt].flow = flow,e[cnt].next = head[u],head[u] = cnt;
        e[++cnt].to = u,e[cnt].dis = -w,e[cnt].flow = 0,e[cnt].next = head[v],head[v] = cnt;
    }
    bool spfa()
    {
        memset(vis,0,sizeof(vis));
        for(int i = 0;i <= t;++i) dis[i] = INF;
        queue<int> Q;
        Q.push(s);
        dis[s] = 0,vis[s] = 1,cal[s] = INF;
        while(!Q.empty())
        {
            int u = Q.front();
            Q.pop();
            vis[u] = 0;//spfa标准操作,清除标记
            for(int i=head[u];i!=-1;i=e[i].next)
            {
                int v = e[i].to,d = e[i].dis,flow = e[i].flow;
                if(flow <= 0) continue;//没有剩余流量可流
                if(dis[v] > dis[u]+d)
                {
                    dis[v] = dis[u]+d;
                    cal[v] = min(cal[u],flow);//更新增广路上的最小流量
                    pre[v] = i;//前驱记录i,因为是链式前向星
                    if(!vis[v]) vis[v] = 1,Q.push(v);
                }
            }
        }
        if(dis[t] == INF) return false;
        return true;
    }
    void MCMF()
    {
        while(spfa())
        {
            int x = t;
            maxflow += cal[t];
            mincost += dis[t]*cal[t];
            while(x!=s)
            {
                int i = pre[x];
                e[i].flow -= cal[t];
                e[i^1].flow += cal[t];
                x = e[i^1].to;
            }
        }
    }
    /*
    超级源点 - 次源点,
    video - video,video - tim
    tim - 超级汇点
    s = 0;
    ss = 1;
    video st : [2 + i,2 * n] to : [2 * n + i,2 * n + m]
    t = 2 * n + m + 1
    */
    int main() {
        int ca;ca = read();
        while(ca--) {
            int k,W;
            n = read(),m = read(),k = read(),W = read();
            memset(head,-1,sizeof(head));
            cnt = -1,maxflow = 0,mincost = 0;
            s = 0,t = 2 * n + m + 1;
            int ss = 1;
            add(s,ss,0,k);
            for(int i = 1;i <= m;++i) {
                u[i] = read(),v[i] = read(),w[i] = read(),op[i] = read();
                add(ss,2 + i,0,1);//ss - video
                add(2 + i,2 * n + i,-w[i],1);//video - video
                add(2 * n + i,t,0,1);
            }
            for(int i = 1;i <= m;++i) {
                for(int j = 1;j <= m;++j) {
                    if(v[i] <= u[j]) {
                        add(2 * n + i,2 + j,(op[i] == op[j]) * W,1);//video - video
                    }
                }
            }
            MCMF();
            printf("%d
    ",abs(mincost));
        }
    
    
       // system("pause");
        return 0;
    }
    View Code
  • 相关阅读:
    CDH5.13 集成Kerberos配置
    使用bash脚本删除文件最后几行
    yolov3模型微调(fine-tune)备忘
    ubuntu 18.04 rsync 命令使用 服务端配置
    python 子包调用 跨目录调用
    [转]命令行界面 (CLI)、终端 (Terminal)、Shell、TTY的联系与区别
    bash shell 判断变量是否在列表中
    TensorFlow 图像分类模型 inception_resnet_v2 模型导出、冻结与使用
    numpy 数组集合运算及下标操作
    Win10 Service'MongoDB Server' failed to start. Verify that you have sufficient privileges to start system services【简记】
  • 原文地址:https://www.cnblogs.com/zwjzwj/p/14778616.html
Copyright © 2020-2023  润新知