https://www.lydsy.com/JudgeOnline/problem.php?id=5333

https://www.luogu.org/problemnew/show/P4620

题意见上。

如果想看官方题解的话,移步:http://www.cnblogs.com/clrs97/p/9064630.html

如果你第一眼没看懂的话,没关系,往下看吧。

应该不难发现a数组构成了一棵有向完全二叉树的形态,于是题意转化成树上点数为k+1的路径点和%m=0。

并且会发现路径会重叠,且当一条路径的1~k个点和另一条路径的2~k+1个点重合时,第一条路径的k+1的点的权值a和第二条路径的1的点的权值b显然要满足限制:

a%m=b%m

并且发现这个限制只对到根路径长为k的点(起个名字叫关键点)不适用换句话讲除了这些点以外的点我们都可以扔掉了,因为除此之外的点的答案都可以通过关键点推算出来。

于是我们只需要对关键点进行dfs就行啦!并且因为到根路径长为k,所以我们只需要统计根到所有合法叶子的路径就行了

设f[i][j]表示i子树中i到叶子的路径答案%m为j时,在原树上的最小代价。(换句话讲,我们要求的就是f[1][0])

再设w[i][j]表示与i点满足限制的点的点权为j的最小代价。

则对于合法的点,f[x][(i+j)%m]=w[x][i]+f[x*2][j]+f[x*2+1][j],不合法的点比如非关键点,或是该点最深叶子到根距离小于k的,需要另行特判。

那么关键就是求w数组了,暴力显然是O(nm)的,于是我们有一种差分的思想去求这个w数组。

首先求出所有与x点满足性质点i的价值和sum[x]+=b[i]。

然后O(n)求出w[x][0]+=(m-a[i])*b[i]。再之后O(2^k*m)求出w[i][j]+=w[i][j-1]+sum[i]就行了。

但是你会发现求w[x][j]的方法对某些值已经等于j的点不公平,他们多加了一遍m*b[i],于是对于每个点,w[x][a[i]]-=m*b[i]。

于是我们有了优秀的求w数组的方法了,可以通过本题。

#include<cmath>
#include<queue>
#include<cstdio>
#include<cctype>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=1e7+;
const int RN=;
const int M=;
const ll INF=1e18;
inline int read(){
int X=,w=;char ch=;
while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
while(isdigit(ch))X=(X<<)+(X<<)+(ch^),ch=getchar();
return w?-X:X;
}
unsigned int SA,SB,SC;
int n,m,k,p,A,B,a[N],b[N],lim,d[RN];
ll w[RN][M],sum[RN],f[RN][M];
unsigned int rng61(){
SA^=SA<<;
SA^=SA>>;
SA^=SA<<;
unsigned int t=SA;
SA=SB;
SB=SC;
SC^=t^SA;
return SC;
}
void gen(){
n=read(),k=read(),m=read(),p=read();
SA=read(),SB=read(),SC=read(),A=read(),B=read();
for(int i=;i<=p;i++)a[i]=read(),b[i]=read();
for(int i=p+;i<=n;i++){
a[i]=rng61()%A+;
b[i]=rng61()%B+;
}
}
void dfs(int x){
int l=x<<,r=x<<|;
if(l>lim){
for(int i=;i<m;i++)f[x][i]=w[x][i];
return;
}
for(int i=;i<m;i++)f[x][i]=INF;
dfs(l);
if(r>lim||d[l]!=d[r]){
for(int i=;i<m;i++)
for(int j=;j<m;j++)
f[x][(i+j)%m]=min(f[x][(i+j)%m],w[x][i]+f[l][j]);
return;
}
dfs(r);
for(int i=;i<m;i++)
for(int j=;j<m;j++)
f[x][(i+j)%m]=min(f[x][(i+j)%m],w[x][i]+f[l][j]+f[r][j]);
}
inline void init(){
memset(sum,,sizeof(sum));
memset(w,,sizeof(w));
}
int main(){
int T=read();
while(T--){
init();gen();k++;
lim=min((<<k)-,n);
for(int i=,l=;i<=n;i++){
int j=i;
while((j>>l)>lim)l+=k;
j>>=l;
a[i]%=m;
sum[j]+=b[i];
w[j][]+=(m-a[i])*b[i];
w[j][a[i]]-=m*b[i];
}
for(int i=lim;i;i--){
d[i]=;
if((i<<)<=lim)d[i]=d[i<<];
d[i]++;
}
for(int i=;i<=lim;i++){
for(int j=;j<m;j++)w[i][j]+=w[i][j-]+sum[i];
}
dfs();
printf("%lld\n",f[][]);
}
return ;
}

+++++++++++++++++++++++++++++++++++++++++++

+本文作者:luyouqi233。               +

+欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+

+++++++++++++++++++++++++++++++++++++++++++

BZOJ5333:[SDOI2018]荣誉称号——题解的更多相关文章

  1. BZOJ5333 [Sdoi2018]荣誉称号 【差分 + 树形dp】

    题目链接 BZOJ5333 题解 看到式子,立即想到二叉树上一个点及其\(k\)个父亲权值和[如果有的话]模\(m\)意义下为\(0\) 考虑如何满足条件 我们假设\(1\)号为第\(0\)层 那么我 ...

  2. [loj#2566][BZOJ5333] [Sdoi2018]荣誉称号 树形dp

    #2566. 「SDOI2018」荣誉称号   休闲游戏玩家小 Q 不仅在算法竞赛方面取得了优异的成绩,还在一款收集钻石的游戏中排名很高. 这款游戏一共有 n 种不同类别的钻石,编号依次为 1 到 n ...

  3. bzoj5333: [Sdoi2018]荣誉称号

    请不要去改题目给的输入,不然你会wa穿... 这么故弄玄虚的题目,肯定要先转换问题 看到这个不断的除2想起别人家的线段树的写法...x的两个孩子是x<<1和x<<1|1 然后问 ...

  4. 【BZOJ5333】荣誉称号(动态规划)

    [BZOJ5333]荣誉称号(动态规划) 题面 BZOJ 洛谷 题解 今天早上贱狗老师讲的.然而我还是不会. 只好照着\(zsy\)代码大力理解一波. 首先观察等式,如果比较熟悉线段树,会发现就是线段 ...

  5. [SDOI2018]荣誉称号

    题解: 并不需要什么算法 首先我们随便画一画就会发现 能画出一颗满二叉树 然后要满足每个点从上往下的路径和都相同(%m意义下) 一个点上可能对应了多个点 然后这样我们可以暴力dp $2^k*m^2+n ...

  6. SDOI2018

    SD的题有点反人类啊... d1t1[SDOI2018]物理实验 感觉比较好想但不太好写,写了一半弃了 d1t2[SDOI2018]战略游戏 建出圆方树,每次建虚树,答案就是虚树上的原点个数减去询问的 ...

  7. SDOI2018:荣誉称号

    题解: https://files.cnblogs.com/files/clrs97/title-solution.pdf Code: #include<cstdio> #include& ...

  8. BZOJ5329: [SDOI2018]战略游戏——题解

    https://www.lydsy.com/JudgeOnline/problem.php?id=5329 https://www.luogu.org/problemnew/show/P4606 省选 ...

  9. 【题解】SDOI2018战略游戏

    被CNST的大小卡了好久.一定要开到18呀…… 首先,遇到这种带各种各样环的图先考虑是不是可以建立圆方树,在圆方树上求出答案.然后转化为圆方树之后,我们就将图转化到了树上.答案非常的明显:只要一个圆点 ...

随机推荐

  1. iOS性能调优工具

    总结: 三类工具 基础工具 (NSLog的方式记录运行时间.) 性能工具.检测各个部分的性能表现,找出性能瓶颈 内存工具.检查内存正确性和内存使用效率 性能工具: 可以衡量CPU的使用,时间的消耗,电 ...

  2. 【二】H.264/MPEG-4 Part 10 White Paper 翻译之 Prediction of Intra Macroblocks

    翻译版权所有,转载请注明出处~ xzrch@2018.09.14 ------------------------------------------------------------------- ...

  3. 「题目代码」P1054~P1059(Java)

    P1054 猴子吃桃 import java.util.*; import java.io.*; import java.math.BigInteger; import java.lang.Chara ...

  4. Qt-QML-QML调用C++类

    QML用来做界面,在不考虑数据的请款下,那是溜溜的,但是,程序是没有不和后台数据交互的,但是了,QML在数据处理方面的效率又是不敢恭维的,这里就出现了QML负责前端界面,而后端使用JS或者C++了. ...

  5. 使用 Fiddler工具模拟post四种请求数据

    post请求主体详解: 对于get请求来说没有请求主体entity-body.对于post请求而言,不会对发送请求的数据格式进行限制,理论上你可以发任意数据,但是服务器能不能处理就是另一回事了.服务器 ...

  6. (C#)设计模式之装饰模式

    1.装饰模式 动态的给一个对象添加一些额外的职责,就添加功能来说,装饰模式比生成子类更加灵活.*装饰模式是为已有功能动态添加更多功能的一种方式.*装饰模式将原有类中的核心职责与装饰功能分离.简化了原有 ...

  7. Java 消息对列

    ActiveMQ入门实例   1.下载ActiveMQ 去官方网站下载:http://activemq.apache.org/ 2.运行ActiveMQ 解压缩apache-activemq-5.5. ...

  8. SIG蓝牙mesh笔记3_网络结构

    目录 3. Mesh Networking 3.1 Bearers 承载层 3.2 Network Layer 网络层 3.2.3 Address validity 地址有效性 3.2.4 Netwo ...

  9. js中的数组对象排序

    一.普通数组排序 js中用方法sort()为数组排序.sort()方法有一个可选参数,是用来确定元素顺序的函数.如果这个参数被省略,那么数组中的元素将按照ASCII字符顺序进行排序.如: var ar ...

  10. C语言中动态内存的分配(malloc,realloc)

    动态内存分配:根据需要随时开辟,随时释放的内存分配方式.分配时机和释放时机完全由程序员决定,由于没有数据声明,这部分空间没有名字.无法像使用变量或数组那样通过变量名或数组名引用其中的数据,只能通过指针 ...