Problem J. Subsequence Sum Queries
Output file: standard output
Time limit: 3 seconds
Memory limit: 256 mebibytes
You have an array a containing n integers and an integer m. You also have q queries to answer. The i-th query is described as a pair of integers (li; ri). Your task is to calculate the number of such subsequences aj1; aj2; : : : ; ajk that li ≤ j1 < j2 < : : : < jk ≤ ri and (aj1 + aj2 + : : : + ajk) mod m = 0. In other words, you need to calculate the number of subsequences of subarray [ali; ali+1; : : : ; ari] such that the sum of elements in each subsequence is divisible by m
Input
The first line contains two integers n and m: the number of elements in a and the modulo (1 ≤ n ≤
2⋅105
2
·
10
5
,1 ≤ m ≤ 20).
The second line contains n integers ai: the elements of array a (0 ≤ ai ≤
109
10
9
).
The third line contains one integer q: the number of queries (1 ≤ q ≤
2⋅105
2
·
10
5
).
Then q lines follow. The i-th of these lines contains two integers li and ri that describe the i-th query (1 ≤ li ≤ ri ≤ n).
Output
Print q lines. The i-th of them must contain the answer for the i-th query. Queries are indexed in the order they are given in the input. Since the answers can be very large, print them modulo 10^9 + 7.
Sample Input | Sample Output |
---|---|
4 3 5 1 3 2 4 1 2 1 3 1 4 2 4 | 2 4 6 4 |
对一个序列,多次询问一段区间当中选取一些数字,和为m的倍数的方法数。
对询问分治,对当前区间的[l,mid],[mid+1,r]做背包,求出选择一些数,对m求余为0,1,2,…m-1方法数。之后,求出区间跨越当前mid的询问,剩下的询问分治处理。这样,时间复杂度就被降到了对数级别。
#include <cstdio>
#include <iostream>
#include <string.h>
#include <string>
#include <map>
#include <queue>
#include <deque>
#include <vector>
#include <set>
#include <algorithm>
#include <math.h>
#include <cmath>
#include <stack>
#include <iomanip>
#define pb push_back
#define mem0(a) memset(a,0,sizeof(a))
#define meminf(a) memset(a,0x3f,sizeof(a))
using namespace std;
typedef long long ll;
typedef long double ld;
typedef double db;
typedef pair<int,int> pp;
const int maxn=200005,inf=0x3f3f3f3f;
const ll llinf=0x3f3f3f3f3f3f3f3f,mod=1e9+7;
const ld pi=acos(-1.0L);
ll ans[maxn],lv[maxn][21],rv[maxn][21];
pp q[maxn];
vector<int> v;
int a[maxn];
ll n,m;
void divide(int l,int r,vector<int> v) {
int mid=(l+r)/2;
for (int i=mid;i<=r;i++)
for (int j=m-1;j>=0;j--)
rv[i][j]=0;
rv[mid][0]=1;
for (int i=mid+1;i<=r;i++) {
for (int j=m-1;j>=0;j--) {
rv[i][j]+=rv[i-1][j]+rv[i-1][(j-a[i]+m)%m];
rv[i][j]%=mod;
}
}
for (int i=mid+1;i>=l;i--)
for (int j=m-1;j>=0;j--)
lv[i][j]=0;
lv[mid+1][0]=1;
for (int i=mid;i>=l;i--) {
for (int j=m-1;j>=0;j--) {
lv[i][j]+=lv[i+1][j]+lv[i+1][(j-a[i]+m)%m];
lv[i][j]%=mod;
}
}
vector<int> ql,qr;
int size=v.size();
for (int i=0;i<size;i++) {
int k=v[i];
if (q[k].first<=mid&&q[k].second>mid) {
ans[k]=lv[q[k].first][0]*rv[q[k].second][0]%mod;
for (int j=1;j<=m-1;j++) {
ans[k]+=lv[q[k].first][j]*rv[q[k].second][m-j];
ans[k]%=mod;
}
} else
if (q[k].second<=mid) ql.pb(k); else qr.pb(k);
}
if (ql.size()&&mid>l) divide(l,mid,ql);
if (qr.size()&&mid+1<r) divide(mid+1,r,qr);
}
int main() {
scanf("%lld%lld",&n,&m);
for (int i=1;i<=n;i++) {
scanf("%d",&a[i]);
a[i]%=m;
}
int qn;
scanf("%d",&qn);
int x,y;
for (int i=1;i<=qn;i++) {
scanf("%d%d",&q[i].first,&q[i].second);
if (q[i].first!=q[i].second) v.pb(i); else
if (a[q[i].first]==0) ans[i]=2; else ans[i]=1;
}
divide(1,n,v);
for (int i=1;i<=qn;i++) {
printf("%lld\n",ans[i]);
}
return 0;
}