版权声明:转载请声明出处,谢谢配合。 https://blog.csdn.net/zxyoi_dreamer/article/details/88359378
洛谷传送门
BZOJ传送门
解析:
我TM也不知道这道题的随机有什么性质可以利用,反正我没看出来。
但是有一点是可以确定的,那么小的 和那么大的 以及完全二叉树的形态不是摆设。
显然一个点最终的权值必须和他的 级祖先相同。
所以我们只需要在前 层维护,将下面的所有点的信息合并上来就行了。
剩下的随便转移出每个点及其子树内部决策完后当前链权值和 为不同值的情况就行了。
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc get_char
#define cs const
#define u32 unsigned int
namespace IO{
inline char get_char(){
static cs int Rlen=1<<20|1;
static char buf[Rlen],*p1,*p2;
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
}
inline int getint(){
re char c;
while(!isdigit(c=gc()));re int num=c^48;
while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
return num;
}
}
using namespace IO;
cs int N=2e7+7,K=2050;
int a[N],b[N];
int n,k,m;
ll totsum[K],sum[K][203],cost[K][203];
ll f[K][203];
int pre[N];
inline void solve(){
int tot=1;
while(tot<=n)tot<<=1;
n=tot;
for(int re i=1;i<=n;++i){
pre[i]=(i>>(k+1))?pre[i>>(k+1)]:i;
totsum[pre[i]]+=b[i];
sum[pre[i]][a[i]]+=b[i];
cost[pre[i]][0]+=(m-a[i])%m*b[i];
}
for(int re i=1;i<(1<<(k+1));++i)
for(int re j=1;j<m;++j){
cost[i][j]=cost[i][j-1]+totsum[i]-m*sum[i][j];
}
for(int re i=(1<<(k-1));i<(1<<k);++i){
for(int re j=0;j<m;++j){
f[i][j]=cost[i<<1][(m-j)%m]+cost[i<<1|1][(m-j)%m];
}
}
for(int re i=(1<<(k-1))-1;i;--i){
for(int re j=0;j<m;++j){
ll t1=1e18,t2=1e18;
for(int re k=0;k<m;++k)
t1=min(t1,f[i<<1][(j+k)%m]+cost[i<<1][k]);
for(int re k=0;k<m;++k)
t2=min(t2,f[i<<1|1][(j+k)%m]+cost[i<<1|1][k]);
f[i][j]=t1+t2;
}
}
ll ans=1e18;
for(int re i=0;i<m;++i)ans=min(ans,f[1][i]+cost[1][i]);
cout<<ans<<"\n";
}
u32 SA,SB,SC;
int p,A,B;
inline u32 rng61(){
SA^=SA<<16;SA^=SA>>5;SA^=SA<<1;
u32 t=SA;SA=SB;SB=SC;SC^=t^SA;
return SC;
}
inline void gen(){
n=getint(),k=getint(),m=getint(),p=getint(),SA=getint(),SB=getint(),SC=getint(),A=getint(),B=getint();
for(int re i=1;i<=p;++i)a[i]=getint()%m,b[i]=getint();
for(int re i=p+1;i<=n;i++){
a[i]=rng61()%A+1;
b[i]=rng61()%B+1;
a[i]%=m;
}
}
inline void init(){
memset(a+1,0,sizeof(int)*n);
memset(b+1,0,sizeof(int)*n);
gen();
memset(totsum,0,sizeof totsum);
memset(sum,0,sizeof sum);
memset(cost,0,sizeof cost);
}
int T;
signed main(){
scanf("%d",&T);
while(T--){
init();
solve();
}
return 0;
}