• Subsequence Sum Queries


    Problem

    有一个长度为(n)的数列,一个数(m)(q)个询问,每次询问区间([l_i, r_i])中有多少子序列的和是(m)的倍数。

    Solution

    分治,将询问分配到各个区间。若一个区间的左区间完全包含某个询问的询问区间,则将该询问分配给该区间的左区间去处理,反之亦然。若某个询问的询问区间跨立于该区间的左右两个区间之间,则在该区间进行处理。

    Code

    /*
     Author: LargeDumpling
     Email: LargeDumpling@qq.com
     Edit History:
    	2018-07-24	File created.
    */
    
    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<vector>
    #include<algorithm>
    using namespace std;
    const int MAXN=200050;
    const int mod=1000000007;
    struct jz
    {
    	int l,r;
    	long long ans;
    	jz() { l=r=ans=0; }
    }Q[MAXN];
    int n,m,qn,a[MAXN];
    long long f[MAXN][20];
    void read1n(int &x)
    {
    	char ch;
    	for(ch=getchar();ch<'0'||'9'<ch;ch=getchar());
    	for(x=0;'0'<=ch&&ch<='9';ch=getchar())
    		x=(x<<1)+(x<<3)+ch-'0';
    	return;
    }
    void calc(int l,int r,vector<int> &q)
    {
    	if(l==r)
    	{
    		int cnt=1;
    		if(a[l]%m==0) cnt++;
    		for(unsigned i=0;i<q.size();i++)
    			Q[q[i]].ans=cnt;
    		return;
    	}
    	int mid=(l+r)>>1;
    	vector<int> qn[2];
    	/*for(int i=l;i<=r;i++)
    	{
    		memset(f[i],0,sizeof(f[i]));
    		f[i][0]++;
    		f[i][a[i]%m]++;
    	}
    	for(int i=mid-1;l<=i;i--)
    	{
    		long long tem[20];
    		memset(tem,0,sizeof(tem));
    		for(int j=0;j<m;j++) // This is not necessary, j is useful only when j==0 or j==a[i]
    			for(int k=0;k<m;k++)
    				tem[(j+k)%m]=(tem[(j+k)%m]+f[i][j]*f[i+1][k]%mod)%mod;
    		memcpy(f[i],tem,sizeof(tem));
    	}
    	for(int i=mid+2;i<=r;i++)
    	{
    		long long tem[20];
    		memset(tem,0,sizeof(tem));
    		for(int j=0;j<m;j++)
    			for(int k=0;k<m;k++)
    				tem[(j+k)%m]=(tem[(j+k)%m]+f[i][j]*f[i-1][k]%mod)%mod;
    		memcpy(f[i],tem,sizeof(tem));
    	}*/
    	memset(f[mid],0,sizeof(f[mid]));
    	f[mid][0]++; f[mid][a[mid]%m]++;
    	memset(f[mid+1],0,sizeof(f[mid+1]));
    	f[mid+1][0]++; f[mid+1][a[mid+1]%m]++;
    	long long tem[20];
    	for(int i=mid-1;l<=i;i--)
    	{
    		memset(tem,0,sizeof(tem));
    		for(int j=0;j<m;j++)
    		{
    			tem[j]=(tem[j]+f[i+1][j])%mod;
    			tem[(j+a[i])%m]=(tem[(j+a[i])%m]+f[i+1][j])%mod;
    		}
    		memcpy(f[i],tem,sizeof(tem));
    	}
    	for(int i=mid+2;i<=r;i++)
    	{
    		memset(tem,0,sizeof(tem));
    		for(int j=0;j<m;j++)
    		{
    			tem[j]=(tem[j]+f[i-1][j])%mod;
    			tem[(j+a[i])%m]=(tem[(j+a[i])%m]+f[i-1][j])%mod;
    		}
    		memcpy(f[i],tem,sizeof(tem));
    	}
    	for(unsigned i=0;i<q.size();i++)
    	{
    		if(Q[q[i]].r<=mid) qn[0].push_back(q[i]);
    		if(mid<Q[q[i]].l) qn[1].push_back(q[i]);
    		if(Q[q[i]].l<=mid&&mid<Q[q[i]].r)
    		{
    			for(int j=0;j<m;j++)
    				Q[q[i]].ans=(Q[q[i]].ans+f[Q[q[i]].l][j]*f[Q[q[i]].r][(m-j)%m])%mod;
    		}
    	}
    	if(qn[0].size()) calc(l,mid,qn[0]);
    	if(qn[1].size()) calc(mid+1,r,qn[1]);
    	return;
    }
    int main()
    {
    	read1n(n); read1n(m);
    	for(int i=1;i<=n;i++)
    		read1n(a[i]);
    	read1n(qn);
    	vector<int> q;
    	for(int i=1;i<=qn;i++)
    	{
    		read1n(Q[i].l);
    		read1n(Q[i].r);
    		q.push_back(i);
    	}
    	calc(1,n,q);
    	for(int i=1;i<=qn;i++)
    		printf("%lld
    ",Q[i].ans);
    	fclose(stdin);
    	fclose(stdout);
    	return 0;
    }
    
    
  • 相关阅读:
    MySQL学习记录
    Python3玩转儿 机器学习(4)
    Python3玩转儿 机器学习(3)
    C#-WebForm-文件上传-FileUpload控件
    C#将WebBowser控件替换为谷歌内核【转】
    各种【icon】矢量图
    WPF 获取鼠标全局坐标【精简】
    winfrom 的 各种效果【需要新浪帐号查看】
    JS 文字波纹效果【插件】
    C# 窗口抖动
  • 原文地址:https://www.cnblogs.com/LargeDumpling/p/9369144.html
Copyright © 2020-2023  润新知