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

qpdk777
这个家伙不懒,但也什么都没有留下搬运于
2025-08-24 22:39:15,当前版本为作者最后更新于2022-08-04 22:23:57,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
如果将所有数列都扩展到 的长度, 级别的数组肯定会时间空间双爆炸。
所以这个题要利用周期性。
不难发现,两个数列的最小正周期为 , 我们真正需要处理的是在这个最小正周期内的交叉积。
尽管如此,若 都是质数,他们的最小正周期也可以很长很长。遍历最小正周期求交叉积依然无法AC。
通过分析那 的数据我们可以发现,若 互质,那么,在一个最小正周期中, 中的每一个元素,都把 中的每一个元素乘了 次,而且只乘了 次。那么我们可以利用分配律,得
$$\sum a_ia_j=\sum(a_i\sum a_j)=\sum a_i\sum a_j=sum_isum_j $$可以在 的复杂度内解决。60pts到手!
以此为启发,我们希望把结论推广到不互质的情况。
若 不互质,通过打表可以
发现猜想:对于 中的每一个元素, 中都有 项与之相乘,且每一个参与相乘的项之间的间隔为 。下面给出严谨证明: 不妨设 ,若 经过 次复制、 经过 次复制后, 能与 对应上,则有
说简单点就是:
我们给 一个微小的扰动,令 ,也就是再把 向后复制一次。那么
$$\begin{aligned} k'&=(m'l_i+t)\bmod l_j \\ &=(ml_i+t+l_i)\bmod l_j \\ &=[(ml_i+t)\bmod l_j + l_i\bmod l_j]\bmod l_j \\ &=(k+l_i)\bmod l_j \\ \end{aligned} $$同理
最大可取到 次,因为这么多次之后就回到最开始的 了。
所有的 都在 上均匀分布,因此间隔为 。
如果对于 的每一项,都以 为间隔遍历 求和,时间复杂度为 ,会超时。
应当首先把 的隔 项和求出来(只需要求出前 项为首的隔 项和即可),然后在遍历 时,直接把刚刚求好的和拿过来乘就可以了。
这样求和的循环外层是 ,内层是 ,求和总计是 ,总的复杂度只有 ,可以AC。
AC代码:
#include<iostream> #include<cstdio> #define M 998244353 using namespace std; inline int read(){ int x = 0, f = 1; char c = getchar(); while(c<'0' || c>'9'){ if(c == '-') f = -1; c = getchar(); } while(c>='0' && c<='9'){ x = (x<<3) + (x<<1) + (c-'0'); c = getchar(); } return x * f; } inline int gcd(int a, int b){ if(b == 0) return a; if(a < b) swap(a, b); return gcd(b, a % b); } inline int lcm(int a, int b){ return (int)1ll * a * b / gcd(a, b); } int n,k,l[200],a[200][1010]; long long ans; long long work(int x, int y){ int c1[1010] = {}, c2[1010] = {}; int s[1010] = {}; if(l[x] > l[y]) swap(x, y); for(int i = 1; i <= l[x]; i++){ c1[i] = a[x][i]; } for(int i = 1; i <= l[y]; i++){ c2[i] = a[y][i]; } int gc = gcd(l[x], l[y]); int lc = lcm(l[x], l[y]); long long ans = 0; for(int i = 1; i <= gc; i++){ long long tmp = 0; for(int j = i; j <= l[y]; j+=gc){ tmp += c2[j]; tmp %= M; } s[i] = tmp; } for(int i = 1; i <= l[x]; i++){ int h = 0; h = i % gc; if(h == 0) h = gc; ans += 1ll * c1[i] * s[h] % M; ans %= M; } ans *= k / lc; ans %= M; return ans; } int main(){ n = read(), k = read(); for(int i = 1; i <= n; i++){ l[i] = read(); for(int j = 1; j <= l[i]; j++){ a[i][j] = read(); } } ans = -1e9; for(int i = 1; i <= n-1; i++){ for(int j = i+1; j <= n; j++) ans = max(ans, work(i, j)); } cout<<ans; return 0; }
- 1
信息
- ID
- 7402
- 时间
- 1000ms
- 内存
- 512MiB
- 难度
- 4
- 标签
- (无)
- 递交数
- 0
- 已通过
- 0
- 上传者