题解:首先考虑问题的弱化版本,即n=2^(k+1)-1,这时候一条链是从叶子到根的(并且是完全二叉树),若根到某节点x的权值之和是y,则其左右任何一个节点到其子树的任意一个点的权值之和都是(m-y)%m。因此可是预处理f[i][j]表示把i的权值改成j的代价,dp[i][j]表示从i出发走到叶子结点的权值是j的最小代价,那么对于叶子,dp[x][i]=f[x][i],否则dp[x][i]=min(dp[y1][j]+dp[y2][j]+f[x][(i-j+m)%m]),其中y1和y2是x的儿子节点,就是枚举当前这个节点的第一位权值。
考虑n比较大的情况,注意到,最终a[x]应当是和a[x/(2^(k+1))]相等的,因此只要确定了前2^(k+1)-1个点的权值,整棵树的权值就确定了。因此只维护那些
x≤2k+1−1
x
≤
2
k
+
1
−
1
的x的f[x][i]。考虑记fa[y]表示y不断往上跳k+1个点,不能跳的时候的位置,若x=fa[y],考虑y对f[x][i]的影响:
f[x][i]+=(i−ay)by,ay≤i
f
[
x
]
[
i
]
+
=
(
i
−
a
y
)
b
y
,
a
y
≤
i
f[x][i]+=(m−ay+i)by,ay>i
f
[
x
]
[
i
]
+
=
(
m
−
a
y
+
i
)
b
y
,
a
y
>
i
而fa数组显然可以O(n)求出,f[x][i]按照上述过程直接计算是O(nm)的,过不了,但其实把f[x][i]改写成对y求和的形式,会发现:
f[x][i]=i∑yby−∑yay×by+m∑ay>iby
f
[
x
]
[
i
]
=
i
∑
y
b
y
−
∑
y
a
y
×
b
y
+
m
∑
a
y
>
i
b
y
因此维护c[x][i]表示
ay>=i
a
y
>=
i
的
by
b
y
的和,这个显然每次c[fa[y]][a[y]]+=b[y],然后最后求个后缀和即可;前两项显然随便维护,因此可以在
O(n+2k+1m)
O
(
n
+
2
k
+
1
m
)
的时间内求出f数组,因此可以在O(n+2^{k+1}m^2)时间内通过本题,最后一个细节是,如果树不是满的,可以加一些b=0的叶子结点扩充到满,可以省略一些细节。
代码十分容易实现:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<climits>
#define gc getchar()
#define K 2100
#define M 210
#define N 20000010
#define lint long long
#define INF (LLONG_MAX/10)
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
inline int inn()
{
int x,ch;while((ch=gc)<'0'||ch>'9');
x=ch^'0';while((ch=gc)>='0'&&ch<='9')
x=(x<<1)+(x<<3)+(ch^'0');return x;
}
unsigned int SA,SB,SC;int p,A,B;
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;
}
int a[N],b[N],fa[N];lint bas[K];
lint c[K][M],f[K][M],dp[K][M];
int main()
{
// freopen("data.in","r",stdin);
for(int T=inn();T;T--)
{
int n=inn(),k=inn(),m=inn(),p=inn(),L=0;while((1<<L)-1<n) L++;
scanf("%u%u%u",&SA,&SB,&SC),A=inn(),B=inn();
for(int i=1;i<=p;i++) a[i]=inn(),b[i]=inn();
for(int i=p+1;i<=n;i++) a[i]=rng61()%A+1,b[i]=rng61()%B+1;
for(int i=1;i<=n;i++) a[i]%=m;
for(int i=n+1;i<=(1<<L)-1;i++) a[i]=b[i]=0;
n=(1<<L)-1;int kv=1;
for(int i=0;i<=k;i++) kv<<=1;
for(int i=1;i<kv;i++)
memset(c[i],0,sizeof(lint)*(m+1)),
fa[i]=i,c[i][a[i]]=b[i],bas[i]=a[i]*b[i];
for(int i=kv;i<=n;i++) c[fa[i]=fa[i/kv]][a[i]]+=b[i],bas[fa[i]]+=a[i]*b[i];
for(int i=1;i<kv;i++)
for(int j=m-2;j>=0;j--) c[i][j]+=c[i][j+1];
for(int i=1;i<kv;i++)
for(int j=0;j<m;j++)
f[i][j]=(lint)j*c[i][0]-bas[i]+(lint)m*c[i][j+1];
for(int i=kv/2;i<kv;i++)
for(int j=0;j<m;j++) dp[i][j]=f[i][j];
for(int i=kv/2-1;i;i--)
for(int j=0;j<m;j++)
{
dp[i][j]=INF;
for(int k=0;k<m;k++)
dp[i][j]=min(dp[i][j],dp[i<<1][k]+dp[i<<1|1][k]+f[i][(j-k+m)%m]);
}
printf("%lld\n",dp[1][0]);
}
return 0;
}