1 条题解
-
0
自动搬运
来自洛谷,原作者为

_ctz
Ádigie šos ök iroг.搬运于
2025-08-24 22:02:01,当前版本为作者最后更新于2019-10-12 14:28:19,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
妈妈我能独立切「SDOI2018R2」的题啦!
虽然这个题不难向下取整满足结合律(并不知道为啥~~asuldb说这很显然~~)。然后把那个鬼畜的条件拆开(懒得打向下取整了):
如果连上边数列就会变成这个样子:

很明显构成了一棵完全二叉树。这个条件就能转化为从任意点出发,向下延伸包含个点的路径权值和模等于。
再看上面那张图,令,列两个式子:
同理,,$a_2\equiv a_{16}\equiv a_{17}\equiv ... a_{23}\pmod m$
也就是说每个点与其子树内向下第层的点最终的权值相等。
这样只要前层的路径满足模等于,下面的所有路径就都满足。的时候要考虑的点数直接降到个。
设为点向下延伸至层路径权值和模为的最小花费。
预处理一个表示将点以及与它相等的点权值全部改为的花费。
直接枚举左右儿子的路径权值转移:
$f(i,j)=\min\{f(i<<1,k)+f(i<<1|1,k)+v(i,(j-k+m)\%m)\}$
从开始倒着,答案就是。复杂度。
代码:
#include <iostream> #include <cstdio> #include <algorithm> #include <cmath> #include <cstring> #define maxn 10000005 #define inf 0x3f3f3f3f using namespace std; inline int read(){ int x=0,y=0; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')y=1;ch=getchar();} while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar(); return y?-x:x; } int n,m,k,a[maxn],b[maxn],id[maxn]; long long f[1<<11][200],v[1<<11][200],tax[1<<11][200]; namespace file{ 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; } void gen(){ n=read(),k=read()+1,m=read(),p=read(),SA=read<unsigned>(),SB=read<unsigned>(),SC=read<unsigned>(),A=read(),B=read(); for(int i = 1; i <= p; i++)a[i]=read()%m,b[i]=read(); for(int i = p + 1; i <= n; i++){ a[i] = (rng61() % A + 1)%m; b[i] = rng61() % B + 1; } } } int main(){ int t=read(); while(t--){ file::gen(); memset(v,0,sizeof v); memset(tax,0,sizeof tax); memset(f,0x3f,sizeof f); for(register int i=1;i<1<<k;++i)tax[id[i]=i][a[i]]=b[i]; for(register int i=1<<k;i<=n;++i)tax[id[i]=id[i/(1<<k)]][a[i]]+=b[i]; for(register int i=1;i<1<<k;++i){ for(register int j=0;j<m;++j){ for(register int k=0;k<j;++k) v[i][j]+=tax[i][k]*(j-k); for(register int k=j+1;k<m;++k) v[i][j]+=tax[i][k]*(j+m-k); } } for(register int i=1<<k-1;i<1<<k;++i) for(register int j=0;j<m;++j) f[i][j]=v[i][j]; for(register int i=(1<<k-1)-1;i;--i) for(register int j=0;j<m;++j) for(register int k=0;k<m;++k) f[i][j]=min(f[i][j],f[i<<1][k]+f[i<<1|1][k]+v[i][(j-k+m)%m]); printf("%lld\n",f[1][0]); for(register int i=1;i<=n;++i)a[i]=b[i]=0; } }
- 1
信息
- ID
- 3595
- 时间
- 10000ms
- 内存
- 500MiB
- 难度
- 6
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者