题目链接:https://codeforces.com/gym/101741/problem/J
题目大意:
你有一个数组a含n个整数,还有一个模数m,你要处理q询问,每个询问给你一段区间[l, r],问你这段区间中有多少个子序列,使得子序列之和模m等于零。注意,空集也算子序列。答案模1e9 + 7。
解题思路:
针对一次询问,我们很容易能得到一个状态转移方程,令dp[i][j] 为区间[x, i](起点未知)内 子序列之和模m等于j 的方案数,则有
dp[i][j] += dp[i][j] + dp[i-1][j] + dp[i-1][(j-a[i]+m) %m]。问题是如果对每次询问都跑一边这个类似01背包的东西,妥妥超时。所以我们想着能不能用分治做。如果我们可以得到[l, mid]的从右往左计算的方案数和[mid+1, r]从左往右计算的方案数,那么如果询问的区间在[l, r]之内且横跨mid,令查询区间为[x, y],答案将为(dp1[x][0] * dp2[y][0]) + sigma(0<i<m) dp1[x][i]*dp[y][m-i]。如果查询不横跨mid,照这样分治下去即可。注意分治不处理单点情况,要特判。
代码如下:
# include <bits/stdc+&#