zoukankan      html  css  js  c++  java
  • 《2019 Multi-University Training Contest 3》

    Fansblog:

    虽然想到了威尔逊定理,但是觉得用不上。

    这里有个结论,那就是相邻的质数之间的最大距离 <= 1e5 + 5。

    有了这个结论,我们就能暴力找到Q。

    然后根据威尔逊定理 (p - 1)! mod p = p - 1。

    那么(p - 1) ! = (p - 1) * (p - 2) * .... Q * ... 1= p - 1.

    所以Q! = (p - 1) / ((p - 1) * (p - 2) * ... (Q + 1) )

    但是这里因为p最大为1e14,所以单纯乘法可能会爆longlong。

    所以对于每个乘法都要用快速乘。

    // Author: levil
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef pair<int,int> pii;
    const int N = 3e5 + 5;
    const int M = 1e6 + 5;
    const LL Mod = 1e9 + 7;
    #define pi acos(-1)
    #define INF 1e9
    #define dbg(ax) cout << "now this num is " << ax << endl;
    
    bool check(LL x) {
        LL m = sqrt(x);
        for(int i = 2;i <= m;++i) {
            if(x % i == 0) return false;
        }
        return true;
    }
    LL quick_c(LL a,LL b,LL mod)
    {
        LL re = 0;
        while(b)
        {
            if(b & 1) re = (re + a) % mod;
            b >>= 1;
            a = (a << 1) % mod;
        }
        return re;
    }
    LL quick_mi(LL a,LL b,LL mod) {
        LL re = 1;
        while(b) {
            if(b & 1) re = quick_c(re,a,mod);
            a = quick_c(a,a,mod);
            b >>= 1;
        }
        return re;
    }
    int main() {
        int ca;scanf("%d",&ca);
        while(ca--) {
            LL p;scanf("%lld",&p);
            LL ans = p - 1,up;
            for(LL i = p - 1;;--i) {
                if(check(i)) {
                    up = i;
                    break;
                }
            }
            for(LL i = up + 1;i <= p - 1;++i) ans = quick_c(ans,quick_mi(i,p - 2,p),p);
            printf("%lld
    ",ans);
        }
    
       // system("pause");
        return 0;
    }
    View Code

    Find the answer:

    这题个人觉得比较直白,很显然最优的取法是排序之后取最大的前缀和。

    那么这点我们可以建一棵类似权值树的树,上面的节点的值代表排序后的a[L]。

    然后每次查询区间最大的和即可。

    注意的是这里不能对值离散化,也就是相同的点要看成不同的,这样方便计算个数。

    但是这题的输出逆天了,必须要每个后面都带一个空格,不然就报pe...

    // Author: levil
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef pair<LL,int> pii;
    const int N = 2e5 + 5;
    const int M = 4e5 + 5;
    const LL Mod = 1e9 + 7;
    #define pi acos(-1)
    #define INF 1e9
    #define dbg(ax) cout << "now this num is " << ax << endl;
    
    int a[N],b[N],ans[N];
    struct QT{int id,x;}p[N];
    struct Node{int L,r,num;LL sum;}node[M << 2];
    bool cmp(QT a,QT b) {
        return a.x < b.x;
    }
    void Pushup(int idx) {
        node[idx].sum = node[idx << 1].sum + node[idx << 1 | 1].sum;
        node[idx].num = node[idx << 1].num + node[idx << 1 | 1].num;
    }
    void build(int L,int r,int idx) {
        node[idx].L = L,node[idx].r = r,node[idx].sum = node[idx].num = 0;
        if(L == r) {
            return ;
        }
        int mid = (L + r) >> 1;
        build(L,mid,idx << 1);
        build(mid + 1,r,idx << 1 | 1);
    }
    void update(int x,LL val,int idx) {
        if(node[idx].L == node[idx].r) {
            node[idx].sum = val;
            node[idx].num = 1;
            return ;
        }
        int mid = (node[idx].L + node[idx].r) >> 1;
        if(mid >= x) update(x,val,idx << 1);
        else update(x,val,idx << 1 | 1);
        Pushup(idx);
    }
    int query(LL up,int idx) {
        if(node[idx].sum <= up) {
            return node[idx].num;
        }
        int num = 0;
        if(node[idx << 1].sum <= up) {
            num += node[idx << 1].num;
            num += query(up - node[idx << 1].sum,idx << 1 | 1);
        }
        else num += query(up,idx << 1);
        return num;
    }
    int main() {
        int ca;scanf("%d",&ca);
        while(ca--) {
            int n,m;scanf("%d %d",&n,&m);
            for(int i = 1;i <= n;++i) scanf("%d",&a[i]),p[i].id = i,p[i].x = a[i];
            sort(p + 1,p + n + 1,cmp);
            for(int i = 1;i <= n;++i) b[p[i].id] = i;
            build(1,n,1);
            for(int i = 1;i <= n;++i) {
                int ma = query(m - a[i],1);
                ans[i] = i - 1 - ma;
                update(b[i],a[i],1);
            }   
            for(int i = 1;i <= n;++i) printf("%d ",ans[i]);
            printf("
    ");
        }
    
        //system("pause");
        return 0;
    }
    View Code

    K Subsequence:

    这题一直想的是怎么dp,居然是用费用流做的。

    但是建模之后确实就很好理解了。

    这里的一个问题就是普通费用流会被卡时间。

    先把spfa换成dij,复杂度依旧不够,要再上原始对偶优化才行。

    / Author: levil
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef pair<LL,int> pii;
    const int N = 4e3 + 5;
    const int M = 4e6 + 5;
    const LL Mod = 1e9 + 7;
    #define pi acos(-1)
    #define INF 1e9
    #define dbg(ax) cout << "now this num is " << ax << endl;
    
    int a[N];
    struct edge {
        int to, capacity, cost, rev;
        edge() {}
        edge(int to, int _capacity, int _cost, int _rev) :to(to), capacity(_capacity), cost(_cost), rev(_rev) {}
    };
    struct Min_Cost_Max_Flow {
        int V, H[N + 5], dis[N + 5], PreV[N + 5], PreE[N + 5];
        vector<edge> G[N + 5];
        //调用前初始化
        void Init(int n) {
            V = n;
            for (int i = 0; i <= V; ++i)G[i].clear();
        }
        //加边
        void add(int from, int to, int cap, int cost) {
            G[from].push_back(edge(to, cap, cost, G[to].size()));
            G[to].push_back(edge(from, 0, -cost, G[from].size() - 1));
        }
        //flow是自己传进去的变量,就是最后的最大流,返回的是最小费用
        pii Min_cost_max_flow(int s, int t, int f) {
            int flow = 0;
            int res = 0; fill(H, H + 1 + V, 0);
            while (f) {//f - 可以达到的最大的最大流
                priority_queue <pair<int, int>, vector<pair<int, int> >, greater<pair<int, int> > > q;
                fill(dis, dis + 1 + V, INF);
                dis[s] = 0; q.push(pair<int, int>(0, s));
                while (!q.empty()) {
                    pair<int, int> now = q.top(); q.pop();
                    int v = now.second;
                    if (dis[v] < now.first)continue;
                    for (int i = 0; i < G[v].size(); ++i) {
                        edge& e = G[v][i];
                        if (e.capacity > 0 && dis[e.to] > dis[v] + e.cost + H[v] - H[e.to]) {
                            dis[e.to] = dis[v] + e.cost + H[v] - H[e.to];
                            PreV[e.to] = v;
                            PreE[e.to] = i;
                            q.push(pair<int, int>(dis[e.to], e.to));
                        }
                    }
                }
                if (dis[t] == INF)break;
                for (int i = 0; i <= V; ++i)H[i] += dis[i];
                int d = f;
                for (int v = t; v != s; v = PreV[v])d = min(d, G[PreV[v]][PreE[v]].capacity);
                f -= d; flow += d; res += d*H[t];
                for (int v = t; v != s; v = PreV[v]) {
                    edge& e = G[PreV[v]][PreE[v]];
                    e.capacity -= d;
                    G[v][e.rev].capacity += d;
                }
            }
            return pii{flow,res};
        }
    };
    Min_Cost_Max_Flow MCMF;
    /*
    i - st[i,n] ed [i + n,2 * n]
    s - 2 * n + 3,t - st - 2 * n + 1,ed - 2 * n + 2
    */
    int main() {
        int ca;scanf("%d",&ca);
        while(ca--) {
            int n,k;scanf("%d %d",&n,&k);
            MCMF.Init(2 * n + 2);
            for(int i = 1;i <= n;++i) scanf("%d",&a[i]);
            int s = 0,t = 2 * n + 2;
            for(int i = 1;i <= n;++i) {
                MCMF.add(s,i,1,0);   
                MCMF.add(i,i + n,1,-a[i]);
                MCMF.add(i + n,2 * n + 1,1,0);
            }
            MCMF.add(2 * n + 1,2 * n + 2,k,0);
            for(int i = 1;i <= n;++i) {
                for(int j = i + 1;j <= n;++j) {
                    if(a[j] >= a[i]) MCMF.add(i + n,j,1,0);
                }
            }
            pii ans = MCMF.Min_cost_max_flow(s,t,INF);
            printf("%d
    ",-ans.second);
        
        }
    
       // system("pause");
        return 0;
    }
    View Code

    Distribution of books:

    首先很直白的一个思路是二分答案,然后去贪心。

    但是这里贪心思考了一会觉得都不是很满足最优的性质。

    我们考虑dp去维护:dp[i]表示前i本书最多可以分配给几个人。

    那么显然有$dp[i] = max{sum_{i = 1}^{j - 1} dp[j] + 1} $满足sum(j + 1 ~ i) <= x。(x为二分的值)

    我们考虑先求得一个前缀和pre[i]。那么对于后面那个就是满足pre[i] - pre[j] <= x。

    转移可得pre[j] >= pre[i] - x。可以发现我们可以维护每个pre上面的最值。

    再一次性查询>=pre[i] - x的即可。

    那么显然可以线段树来维护,不过要先对前缀和进行离散化。

    // Author: levil
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef pair<int,int> pii;
    const int N = 2e5 + 5;
    const int M = 5e5 + 5;
    const LL Mod = 1e9 + 7;
    #define pi acos(-1)
    #define INF 1e16
    #define dbg(ax) cout << "now this num is " << ax << endl;
    
    int a[N],n,k,len;
    LL pre[N],b[N];//dp[i] - 前i本书能分配的最多人数
    struct Node{int L,r,x;}node[N << 2];
    void Pushup(int idx) {
        node[idx].x = max(node[idx << 1].x,node[idx << 1 | 1].x);
    }
    void build(int L,int r,int idx) {
        node[idx].L = L,node[idx].r = r,node[idx].x = 0;
        if(L == r) {
            return ;
        }
        int mid = (L + r) >> 1;
        build(L,mid,idx << 1);
        build(mid + 1,r,idx << 1 | 1);
    }
    void update(int x,int idx,int val) {
        if(node[idx].L == node[idx].r) {
            node[idx].x = max(node[idx].x,val);
            return ;
        }
        int mid = (node[idx].L + node[idx].r) >> 1;
        if(mid >= x) update(x,idx << 1,val);
        else update(x,idx << 1 | 1,val);
        Pushup(idx);
    }   
    int query(int L,int r,int idx) {
        if(node[idx].L >= L && node[idx].r <= r) return node[idx].x;
        int mid = (node[idx].L + node[idx].r) >> 1,mx = 0;
        if(mid >= L) mx = max(mx,query(L,r,idx << 1));
        if(mid < r) mx = max(mx,query(L,r,idx << 1 | 1));
        return mx;
    }
    bool check(LL x) {
        int mx = 0;
        build(1,len,1);
        if(pre[1] <= x) {
            mx = 1;
            update(a[1],1,1);
        } 
        for(int i = 2;i <= n;++i) {
            LL ma = pre[i] - x;
            int pos = lower_bound(b + 1,b + len + 1,ma) - b;
            if(pos == len + 1) {
                if(pre[i] <= x) {
                    update(a[i],1,1);
                    mx = max(mx,1);
                }
                continue;
            }
            int ans = query(pos,len,1);
            if(ans == 0) {
                if(pre[i] <= x) {
                    update(a[i],1,1);
                    mx = max(mx,1);
                }
            }
            else {
                update(a[i],1,ans + 1);
                mx = max(mx,ans + 1);
            }
        }
        return mx >= k;
    }
    int main() {
        int ca;scanf("%d",&ca);
        while(ca--) {
            scanf("%d %d",&n,&k);
            for(int i = 1;i <= n;++i) scanf("%d",&a[i]);
            memset(pre,0,sizeof(pre));
            int tot = 0;
            for(int i = 1;i <= n;++i) pre[i] = pre[i - 1] + a[i],b[++tot] = pre[i];
            sort(b + 1,b + n + 1);
            len = unique(b + 1,b + n + 1) - b - 1;
            for(int i = 1;i <= n;++i) {
                a[i] = lower_bound(b + 1,b + len + 1,pre[i]) - b;
            }
            LL L = -INF,r = INF,ans;
            while(L <= r) {
                LL mid = (L + r) >> 1;
                if(check(mid)) ans = mid,r = mid - 1;
                else L = mid + 1;
            }
            printf("%lld
    ",ans);
        }
    
        //system("pause");
        return 0;
    }
    View Code

    Blow up the city:

    这题其实和洛谷灾难那题差不多。

    我们建立虚点对所有中央指挥点连边。

    考虑最终形成的支配树,计算出每个点的深度就可以得出。

    对于两个点u,v的答案就是dep[u] + dep[v] - dep[lca[u,v]] - 1.这里要把虚点的贡献减掉。

    // Author: levil
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef pair<int,int> pii;
    const int N = 2e5 + 5;
    const int M = 5e5 + 5;
    const LL Mod = 1e9 + 7;
    #define pi acos(-1)
    #define INF 1e16
    #define dbg(ax) cout << "now this num is " << ax << endl;
    
    vector<int> G[N],RG[N],T[N];
    int dfn[N],rk[N],idom[N],semi[N],fa[N],out[N],dep[N],f[N][20],lg[N],n,m,tim = 0;
    namespace Node{
        int fa[N],val[N];
        void init() {
            for(int i = 1;i <= n + 1;++i) fa[i] = i,val[i] = 0;
        }
        int Find(int x) {
            if(x == fa[x]) return x;
            int ffa = fa[x];
            fa[x] = Find(fa[x]);
            if(dfn[semi[val[x]]] > dfn[semi[val[ffa]]]) val[x] = val[ffa];
            return ffa;
        }
        void Merge(int x,int y) {
            x = Find(x),y = Find(y);
            fa[y] = x;
        }
    };
    void dfs(int u) {
        dfn[u] = ++tim;
        rk[tim] = u;
        for(auto v : G[u]) {
            if(!dfn[v]) {
                fa[v] = u;
                dfs(v);
            }
        }
    }
    void dfs2(int u,int ffa) {
        f[u][0] = ffa;
        dep[u] = dep[ffa] + 1;
        for(int i = 1;i <= lg[dep[u]];++i) f[u][i] = f[f[u][i - 1]][i - 1];
        for(auto v : G[u]) {
            if(v == ffa) continue;
            dfs2(v,u);
        }
    }
    int LCA(int x,int y) {
        if(dep[x] < dep[y]) swap(x,y);
        while(dep[x] > dep[y]) x = f[x][lg[dep[x] - dep[y]] - 1];
        if(x == y) return x;
        for(int i = lg[dep[x]];i >= 0;--i) {
            if(f[x][i] != f[y][i]) x = f[x][i],y = f[y][i];
        }
        return f[x][0];
    }
    int getmin(int x,int y) {
        return dfn[x] < dfn[y] ? x : y;
    }
    void solve() {
        dfs(n + 1);
        dfn[0] = n + 2;
        Node::init();
        for(int i = n + 1;i >= 1;--i) {
            int x = rk[i];
            for(auto v : RG[x]) {
                if(dfn[v] < dfn[x]) semi[x] = getmin(semi[x],v);
                else {
                    Node::Find(v);    
                    semi[x] = getmin(semi[x],semi[Node::val[v]]);
                }
            }
            for(auto v : T[x]) {
                Node::Find(v);
                int ma = Node::val[v];
                if(semi[ma] == x) idom[v] = x;
                else idom[v] = ma;
            }
            Node::val[x] = x;
            Node::Merge(fa[x],x);
            T[semi[x]].push_back(x);
        }
        for(int i = 2;i <= n + 1;++i) {
            int x = rk[i];
            if(idom[x] != semi[x]) idom[x] = idom[idom[x]];
        }
        for(int i = 1;i <= n + 1;++i) G[i].clear();
        for(int i = 2;i <= n + 1;++i) {
            int x = rk[i];
            if(idom[x]) {
                G[idom[x]].push_back(x);
            }
        }
        dfs2(n + 1,0);
    }
    void init() {
        for(int i = 1;i <= n + 1;++i) {
            dfn[i] = semi[i] = idom[i] = out[i] = 0;
            G[i].clear();
            RG[i].clear();
            T[i].clear();
        }
        tim = 0;
    }
    int main() {
        for(int i = 1;i < N;++i) lg[i] = lg[i - 1] + (1 << lg[i - 1] == i);
        int ca;scanf("%d",&ca);
        while(ca--) {  
            scanf("%d %d",&n,&m);
            init(); 
            while(m--) {
                int u,v;scanf("%d %d",&u,&v);
                G[v].push_back(u);
                RG[u].push_back(v);
                out[u]++;
            }
            for(int i = 1;i <= n;++i) {
                if(out[i] == 0) {
                    G[n + 1].push_back(i);
                    RG[i].push_back(n + 1);
                } 
            }
            solve();
            int q;scanf("%d",&q);
            while(q--) {
                int a,b;scanf("%d %d",&a,&b);
                int ans = dep[a] + dep[b] - dep[LCA(a,b)] - 1;
                //printf("a is %d b is %d lca is %d
    ",a,b,LCA(a,b));
                printf("%d
    ",ans);
            }
        }
    
       // system("pause");
        return 0;
    }
    /*
    2
    9 9
    1 2
    3 4
    3 5
    4 6
    4 7
    5 7
    6 8
    7 8
    7 9
    10
    1 2
    1 3
    4 7
    4 5
    9 5
    3 8
    6 4
    
    */
    View Code
  • 相关阅读:
    后缀零
    vs2019 MFC的安装 解决 此项目需要 MFC 库。从 Visual Studio 安装程序(单个组件选项卡)为正在使用的任何工具集和体系结构安装它们。
    矩形切割
    fsync: failed to connect to feed.openvas.org (89.146.224.58)
    How to Install GVM Trial With VMware Workstation Player/Pro
    GVM 21.04 (stable, initial release 20210416)
    gitlab 升级相关
    Adobe Reader XI 11.0.23 简体中文版
    gofileserver GO HTTP 文件下载服务器
    KVM 中安装 Windows 10 虚拟机、CentOS 8 虚拟机及快照操作
  • 原文地址:https://www.cnblogs.com/zwjzwj/p/15142560.html
Copyright © 2011-2022 走看看