zoukankan      html  css  js  c++  java
  • BZOJ5333 [Sdoi2018]荣誉称号 【差分 + 树形dp】

    题目链接

    BZOJ5333

    题解

    看到式子,立即想到二叉树上一个点及其(k)个父亲权值和【如果有的话】模(m)意义下为(0)
    考虑如何满足条件
    我们假设(1)号为第(0)
    那么我们先满足第(k)层的条件
    由于第(k + 1)层也满足条件
    由同余的性质第(k + 1)层的权值等于第(1)层的权值
    同理可以往下推

    所以在超过第(k)层后,每个节点往上都会与某个节点相联结
    我们就不妨求出(w[i][j])表示前(k)层的节点(i)权值变为(j)所需要付出的最小代价
    显然(w[i][j])就是与(i)联结的包括(i)的所有节点权值加到(j)的代价和
    暴力转移是(O(nm))的,但是发现加的是一个等差数列
    所以我们双层差分即可(O(n + 2^{k}m))计算出(w[i][j])

    然后就可以树形(dp)
    有了(w[i][j]),我们只需求出第(k)层往上权值和为(0)的最小代价,其它点就默认满足要求了
    我们设(f[i][j])表示点(i)到第(k)层权值和为(j)的最小代价即可

    交上去第一个点(WA)了,为什么?
    考虑(f[i][j])表示的是到第(k)层权值和为(j),如果这个第(k)层根本不存在,这个限制就没有意义了
    换言之,(i)取什么值都不影响结果
    怎么解决这个问题?
    我们人为加满至第(k)层,多出来的节点的(b)设为(0)即可

    复杂度(O(n + 2^{k}m^2))

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #include<map>
    #define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
    #define REP(i,n) for (int i = 1; i <= (n); i++)
    #define mp(a,b) make_pair<int,int>(a,b)
    #define cls(s) memset(s,0,sizeof(s))
    #define cp pair<int,int>
    #define LL long long int
    using namespace std;
    const int maxn = 100005,maxm = 100005,N = 10000005;
    const LL INF = 100000000000000000ll;
    inline int read(){
    	int out = 0,flag = 1; char c = getchar();
    	while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}
    	while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
    	return out * flag;
    }
    LL b[N];
    int a[N],fa[N],n,m,K;
    unsigned int SA, SB, SC;int p, AA, BB;
    unsigned int rng61(){
        SA ^= SA << 16;
        SA ^= SA >> 5;
        SA ^= SA << 1;
        unsigned int t = SA;
        SA = SB;
        SB = SC;
        SC ^= t ^ SA;
        return SC;
    }
    void gen(){
        scanf("%d%d%d%d%u%u%u%d%d", &n, &K, &m, &p, &SA, &SB, &SC, &AA, &BB);
        for(int i = 1; i <= p; i++)scanf("%d%lld", &a[i], &b[i]);
        for(int i = p + 1; i <= n; i++){
            a[i] = rng61() % AA + 1;
            b[i] = rng61() % BB + 1;
        }
    	if (n < (1 << K + 1) - 1){
    		for (int i = n + 1; i < (1 << K + 1); i++)
    			a[i] = b[i] = 0;
    		n = (1 << K + 1) - 1;
    	}
    	for (int i = 1; i <= n; i++){
    		a[i] %= m;
    		if (i < (1 << K + 1)) fa[i] = i;
    		else fa[i] = fa[i / (1 << K + 1)];
    	}
    }
    LL w[2100][205];
    void calw(){
    	int u; cls(w);
    	for (int i = 1; i <= n; i++){
    		u = fa[i];
    		if (!a[i]){
    			w[u][1] += b[i];
    		}
    		else {
    			w[u][0] += b[i] * (m - a[i]);
    			if (a[i] > 1){
    				w[u][1] -= b[i] * (m - a[i] - 1);
    				w[u][a[i]] -= b[i] * m;
    			}
    			else {
    				w[u][1] -= 2 * b[i] * (m - 1);
    			}
    			w[u][a[i] + 1] += b[i] * m;
    		}
    	}
    	int E = min(n,(1 << K + 1) - 1);
    	for (int i = 1; i <= E; i++){
    		for (int j = 1; j < m; j++)
    			w[i][j] += w[i][j - 1];
    		for (int j = 1; j < m; j++)
    			w[i][j] += w[i][j - 1];
    	}
    }
    LL f[2100][205];
    void work(){
    	int E = min((1 << K + 1) - 1,n);
    	for (int i = E; i; i--){
    		int ls = i << 1,rs = i << 1 | 1;
    		if (ls > E) ls = 0;
    		if (rs > E) rs = 0;
    		if (!ls && !rs){
    			for (int j = 0; j < m; j++) f[i][j] = w[i][j];
    		}
    		else if (ls && !rs){
    			for (int j = 0; j < m; j++){
    				f[i][j] = INF;
    				for (int k = 0; k < m; k++){
    					f[i][j] = min(f[i][j],w[i][(m + j - k) % m] + f[ls][k]);
    				}
    			}
    		}
    		else {
    			for (int j = 0; j < m; j++){
    				f[i][j] = INF;
    				for (int k = 0; k < m; k++){
    					f[i][j] = min(f[i][j],w[i][(m + j - k) % m] + f[ls][k] + f[rs][k]);
    				}
    			}
    		}
    	}
    	printf("%lld
    ",f[1][0]);
    }
    int main(){
    	int T = read();
    	while (T--){
    		gen();
    		calw();
    		work();
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    Unknown host mirrors.opencas.cn You may need to adjust the proxy settings in Gradle 报错及解决办法
    Design editor is unavaiable until next gradle sync报错及解决办法
    mkdir创建目录失败
    读书笔记之梦断代码(三)
    Android学习——更新数据
    Android学习——添加数据
    Android学习——升级数据库
    Android学习——创建数据库
    开课第十一周周总结
    Android学习——数据库简介
  • 原文地址:https://www.cnblogs.com/Mychael/p/9202013.html
Copyright © 2011-2022 走看看