zoukankan      html  css  js  c++  java
  • GX/GZOI2019 day2 解题报告

    GX/GZOI2019 day2 解题报告

    题目链接

    逼死强迫症

    旅行者

    旧词

    t1 逼死强迫症

    显然地,记 (f(i)) 为长度为 (i) 的木板的答案,可得: (\)

    [f(i)=egin{cases} 0 quad ······························ quad (i in [0,2]) \ f(i-1)+f(i-2)+2 imes pre(i-3) quad ·· quad ( i in [3,+infty])) end{cases}]

    其中 (pre(n)=Sigma_{i=0}^n fib(i));
    然后矩阵快速幂就行了,复杂度 (O(T imes 5^3 imes log_2n))
    代码:

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    typedef long long ll;
    int in() {
    	int x=0;char c=getchar();bool f=false;
    	while(c<'0'||c>'9') f|=c=='-', c=getchar();
    	while(c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48), c=getchar();
    	return f?-x:x;
    }
    
    const int mod = 1e9+7;
    
    inline void add(int &x, int y) { x+=y; if(x>=mod) x-=mod; }
    inline void sub(int &x, int y) { x-=y; if(x<0) x+=mod; }
    
    struct matrix {
    	int a[5][5];
    
    	matrix(int x=0) {
    		memset(a, 0, sizeof(a));
    		if(x) for(int i=0;i<5;++i) a[i][i]=x;
    	}
    
    	inline int * operator [] (const int x) { 
    		return a[x];
    	}
    
    	inline matrix operator * (matrix b) const {
    		matrix ret;
    		for(int i=0;i<5;++i)
    			for(int j=0;j<5;++j)
    				for(int k=0;k<5;++k)
    					add(ret[i][j], (ll)a[i][k]*b[k][j]%mod);
    		return ret;
    	}
    };
    
    matrix qpow(matrix base, int b) {
    	matrix ret(1);
    	for(;b;b>>=1, base=base*base)
    		if(b&1) ret=ret*base;
    	return ret;
    }
    
    int main() {
    
        //freopen("obsession.in", "r", stdin);
        //freopen("obsession.out", "w", stdout);
    
        int T=in(), n;
    
        while(T--) {
            n=in();
            if(n<=2) {
                puts("0");
                continue;
            }
    		matrix a, b;
    		a[0][0]=2, a[0][1]=0, a[0][2]=2, a[0][3]=1, a[0][4]=1;
    
    		b[0][0]=1, b[0][1]=1;
    		b[1][0]=1;
    		b[2][0]=2, b[2][2]=1;
    		b[3][2]=1, b[3][3]=1, b[3][4]=1;
    		b[4][2]=1, b[4][3]=1;
    
    		a=a*qpow(b, n-3);
    		
    		printf("%d
    ", a[0][0]);
        }
    
        return 0;
    }
    

    t2 旅行者

    可以正向/反向建边,跑两遍 (dijkstra),染色(颜色为 (k) 个节点的编号),只有两边的颜色不同才造成贡献。这里没有写

    有一种比较暴力的想法:
    新建两个节点 (S,T),将 (k) 个点分成两组,(S) 向一组连边,另一组向 (T) 连边,边权都为 (0),跑最短路即可;
    不难想到按二进制分组:枚举 (k) 的每一个二进制位,分成两组,做 (log_2k) 次。

    代码:

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <vector>
    #include <queue>
    typedef long long ll;
    typedef std::pair<ll, int> pli;
    int in() {
        int x=0;char c=getchar();bool f=false;
        while(c<'0'||c>'9') f|=c=='-', c=getchar();
        while(c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48), c=getchar();
        return f?-x:x;
    }
    template<typename T>inline void chk_min(T &_, T __) { _=_<__?_:__; }
    
    const int N = 1e5+5;
    
    struct edge {
        int next, to, w;
    }e[N*6];
    int cnt, head[N];
    
    int a[N];
    
    ll d[N];
    
    bool vis[N];
    
    inline void jb(const int u, const int v, const int w) {
        e[++cnt]=(edge){head[u], v, w}, head[u]=cnt;
    }
    
    std::priority_queue <pli> q;
    ll dijkstra(const int s, const int t) {
        memset(d, 0x3f, sizeof(d));
        memset(vis, 0, sizeof(vis));
        q.push(pli(0, s));
        d[s]=0;
        while(!q.empty()) {
            int u=q.top().second; q.pop();
            if(vis[u]) continue;
            vis[u]=1;
            for(int i=head[u];i;i=e[i].next) {
                int v=e[i].to, w=e[i].w;
                if(d[u]+w<d[v]) {
                    d[v]=d[u]+w;
                    q.push(pli(-d[v], v));
                }
            }
        }
        return d[t];
    }
    
    ll spfa_(const int s, const int t) {
        memset(d, 0x3f, sizeof(d));
        q.push(pli(0, s));
        d[s]=0, vis[s]=1;
        while(!q.empty()) {
            int u=q.top().second; q.pop();
            vis[u]=0;
            for(int i=head[u];i;i=e[i].next) {
                int v=e[i].to, w=e[i].w;
                if(d[u]+w<d[v]) {
                    d[v]=d[u]+w;
                    if(!vis[v])
                        q.push(pli(-d[v], v)), vis[v]=true;
                }
            }
        }
        return d[t];
    }
    
    std::deque <int> Q;
    ll spfa(const int s, const int t) {
        memset(d, 0x3f, sizeof(d));
        Q.push_back(s);
        d[s]=0, vis[s]=1;
        while(!Q.empty()) {
            int u=Q.front(); Q.pop_front();
            vis[u]=0;
            for(int i=head[u];i;i=e[i].next) {
                int v=e[i].to, w=e[i].w;
                if(d[u]+w<d[v]) {
                    d[v]=d[u]+w;
                    if(!vis[v]) {
                        if(Q.empty()) Q.push_back(v);
                        else if(d[Q.front()]<d[v]) Q.push_back(v);
                        else                  Q.push_front(v);
                        vis[v]=true;
                    }
                }
            }
        }
        return d[t];
    }
    
    inline void init() {
        cnt=1;
        memset(head, 0, sizeof(head));
    }
    
    int main() {
        //freopen("tourist.in", "r", stdin);
        //freopen("tourist.out", "w", stdout);
        int T=in();
        while(T--) {
            int n=in(), m=in(), k=in();
            init();
            for(int i=1, x, y, z;i<=m;++i) {
                x=in(), y=in(), z=in();
                jb(x, y, z);
            }
            for(int i=1;i<=k;++i) a[i]=in();
    
            int s=0, t=n+1;
            ll res=1ll<<60ll;
            for(int l=1;l<=k;l<<=1) {
                for(int i=1;i<=k;++i)
                    if(i&l) jb(s, a[i], 0);
                    else    jb(a[i], t, 0);
                chk_min(res, spfa(s, t));
                for(int i=1;i<=k;++i)
                    if(i&l) head[s]=e[head[s]].next, --cnt;
                    else    head[a[i]]=e[head[a[i]]].next, --cnt;
    
                for(int i=1;i<=k;++i)
                    if(!(i&l)) jb(s, a[i], 0);
                    else       jb(a[i], t, 0);
                chk_min(res, spfa(s, t));
                for(int i=1;i<=k;++i)
                    if(!(i&l)) head[s]=e[head[s]].next, --cnt;
                    else       head[a[i]]=e[head[a[i]]].next, --cnt;
            }
            printf("%lld
    ", res);
        }
        return 0;
    }
    

    t3 旧词

    先考虑 (k=1) 的做法;
    显然地,要离线处理,按 (x) 排好序,每一次把 (1)~(x) 的贡献维护好;
    主要思想:对于深度为 (d) 的节点 (u),把 (d) 均摊到 (1)~(u) 这条链上,查询 (y) 时计算 (1)~(y) 的和即可。
    如果 (k=1),则每次修改只需把 (1)~(x) 的权值每次加 (1)

    同样地,当 (k e 1) 时,不难发现,给每个节点一个权值(设点为 (u)) ((dep_u)^k-(dep_u-1)^k),每次修改只需要加一次这个权值就行了。

    树剖维护即可。

    代码:

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    typedef long long ll;
    int in() {
        int x=0;char c=getchar();bool f=false;
        while(c<'0'||c>'9') f|=c=='-', c=getchar();
        while(c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48), c=getchar();
        return f?-x:x;
    }
    const int N = 5e4+5, mod = 998244353;
    
    struct edge {
        int next, to;
    }e[N];
    int cnt=1, head[N], dep[N], fro[N], siz[N], hson[N], dfn[N], pos[N], fa[N];
    int n, m, k;
    
    //heavy-light decomposition begin
    void dfs_h(const int u) {
        siz[u]=1;
        for(int i=head[u];i;i=e[i].next) {
            int v=e[i].to;
            dep[v]=dep[u]+1;
            fa[v]=u;
            dfs_h(v);
            siz[u]+=siz[v];
            if(siz[v]>siz[hson[u]]) hson[u]=v;
        }
    }
    
    void dfs_f(const int u, const int tp) {
        fro[u]=tp, dfn[u]=++dfn[0], pos[dfn[u]]=u;
        if(hson[u]) dfs_f(hson[u], tp);
        for(int i=head[u];i;i=e[i].next)
            if(e[i].to!=hson[u])
                dfs_f(e[i].to, e[i].to);
    }
    
    inline void prep() {
        dep[1]=1;
        dfs_h(1);
        dfs_f(1, 1);
    }
    //heavy-light decomposition end
    
    //segment_tree begin
    
    inline void add(int &_, int __) { _+=__; if(_>=mod) _-=mod; }
    
    int qpow(int base, int b) {
        int ret=1;
        for(;b;b>>=1, base=(ll)base*base%mod)
            if(b&1) ret=(ll)ret*base%mod;
        return ret;
    }
    
    struct segment_tree {
    #define lson tl, mid, p<<1
    #define rson mid+1, tr, p<<1|1
        int t[N<<2], base[N<<2], lazy[N<<2];
        inline void push_up(const int p) {
            t[p]=t[p<<1]+t[p<<1|1];
            if(t[p]>=mod) t[p]-=mod;
        }
        inline void spread(const int p) {
            add(t[p<<1], (ll)base[p<<1]*lazy[p]%mod);
            add(t[p<<1|1], (ll)base[p<<1|1]*lazy[p]%mod);
            add(lazy[p<<1], lazy[p]), add(lazy[p<<1|1], lazy[p]);
            lazy[p]=0;
        }
        void build(const int tl, const int tr, const int p) {
            if(tl==tr) {
                base[p]=qpow(dep[pos[tl]], k)-qpow(dep[pos[tl]]-1, k);
                if(base[p]<0) base[p]+=mod;
                return ;
            }
            int mid=(tl+tr)>>1;
            build(lson), build(rson);
            base[p]=base[p<<1]+base[p<<1|1];
            if(base[p]>=mod) base[p]-=mod;
        }
        void update(const int l, const int r, const int tl, const int tr, const int p) {
            if(l<=tl&&tr<=r)
                return (void)(add(t[p], base[p]), add(lazy[p], 1));
            int mid=(tl+tr)>>1;
            if(lazy[p]) spread(p);
            if(mid>=l) update(l, r, lson);
            if(mid<r)  update(l, r, rson);
            push_up(p);
        }
        int query(const int l, const int r, const int tl, const int tr, const int p) {
            if(l<=tl&&tr<=r) return t[p];
            int mid=(tl+tr)>>1, ret=0;
            if(lazy[p]) spread(p);
            if(mid>=l) ret=query(l, r, lson);
            if(mid<r)  add(ret, query(l, r, rson));
            return ret;
        }
    #undef lson
    #undef rson
    }T;
    //segment_tree end
    
    struct ask {
        int x, y, id;
    }q[N];
    int res[N];
    
    inline bool cmpx(const ask &a, const ask &b) {
        return a.x < b.x;
    }
    
    void update(int u, int v) {
        while(fro[u]!=fro[v]) {
            if(dep[fro[u]]>dep[fro[v]]) std::swap(u, v);
            T.update(dfn[fro[v]], dfn[v], 1, n, 1);
            v=fa[fro[v]];
        }
        if(dep[u]>dep[v]) std::swap(u, v);
        T.update(dfn[u], dfn[v], 1, n, 1);
    }
    
    int query(int u, int v) {
        int ret=0;
        while(fro[u]!=fro[v]) {
            if(dep[fro[u]]>dep[fro[v]]) std::swap(u, v);
            add(ret, T.query(dfn[fro[v]], dfn[v], 1, n, 1));
            v=fa[fro[v]];
        }
        if(dep[u]>dep[v]) std::swap(u, v);
        add(ret, T.query(dfn[u], dfn[v], 1, n, 1));
        return ret;
    }
    
    int main() {
        //freopen("poetry.in", "r", stdin);
        //freopen("poetry.out", "w", stdout);
        n=in(), m=in(), k=in();
        for(int i=2;i<=n;++i) {
            int f=in();
            e[++cnt]=(edge){head[f], i};
            head[f]=cnt;
        }
        prep();
        T.build(1, n, 1);
    
        for(int i=1;i<=m;++i) q[i]=(ask){in(), in(), i};
        std::sort(q+1, q+1+m, cmpx);
    
        for(int i=1, now=0;i<=m;++i) {
            while(now<q[i].x) {
                ++now;
                update(1, now);
            }
            res[q[i].id]=query(1, q[i].y);
        }
    
        for(int i=1;i<=m;++i) printf("%d
    ", res[i]);
        return 0;
    }
    
  • 相关阅读:
    【Django】CSRF token missing or incorrect问题处理
    【Go】Hello World!
    【Element UI】axios 与 request.js配置
    【Element UI】 使用弹窗组件关闭时的传值修改 / 报错:Avoid mutating a prop directly since the value will be overwritten
    【Pyqt5】QT designer与 pycharm的配置
    Python 冒泡排序的优化
    skywalking/8.5部署
    nginx缓存加速笔记
    记拼多多快团团api php 调用接口类
    记拼多多 快团团 php 快团团创建团购接口 增加商品库存接口 规格创建 上传商品图等接口
  • 原文地址:https://www.cnblogs.com/15owzLy1-yiylcy/p/10722021.html
Copyright © 2011-2022 走看看