您的位置:首页 > 其它

GYM 101102 J.Divisible Numbers(数论+容斥原理)

2017-03-17 13:59 330 查看
Description

给出一个长度为n的序列,q次查询,每次查询给出区间[l,r]和一个数s,s的二进制从右往左第i位表示i是否出现,统计[l,r]中有多少数可以被s所表示的这些出现的某一个数整除

Input

第一行一整数T表示用例组数,每组用例首先输入两整数n和q分别表示序列长度和查询数,之后n个数a[i]表示该序列,最后q行每行三个整数l,r,s分别表示查询的区间和1~10这十个数是否出现的二进制表示

(1<=n,q<=1e5,1<=a[i]<=1e9,1<=l<=r<=n,1<=s<=1023)

Output

对于每次查询,输出[l,r]中有多少数被出现的这些数中的某一个整除

Sample Input

1

4 2

2 5 3 8

1 3 2

2 4 355

Sample Output

1

3

Solution

枚举这1023种情况,求出每种情况出现的数字的最小公倍数,去重之后只有47种可能,num[i][j]表示a序列前i个数中有多少数可以被这47个数中的第j个整除,对于每次查询,假设出现的数是b[1]~b[res],如果b序列中某个数可以整除另一个,那么把大的数去掉,因为查询大的数没有意义,例如2 4同时出现,那么被4整除的数字一定被2整除,只需要统计被2整除的数字即可,4可以去掉,去掉这些情况后,用容斥定理计数即可,res最多为5,所以整体时间复杂度是O(47n+31q)

Code

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<ctime>
using namespace std;
typedef long long ll;
#define INF 0x3f3f3f3f
#define maxn 100001
int T,n,q,a[666],c[2525],cnt,num[maxn][50],b[11];
int gcd(int a,int b)
{
return b?gcd(b,a%b):a;
}
int lcm(int a,int b)
{
return a*b/gcd(a,b);
}
void init()
{
cnt=0;
for(int k=2;k<1024;k+=2)
{
int temp=1;
for(int i=1;i<10;i++)
if(k&(1<<i))temp=lcm(temp,i+1);
a[cnt++]=temp;
}
sort(a,a+cnt);
cnt=unique(a,a+cnt)-a;
printf("cnt=%d\n",cnt);
for(int i=0;i<cnt;i++)c[a[i]]=i;
}
int main()
{
init();
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&q);
memset(num[0],0,sizeof(num[0]));
for(int i=1;i<=n;i++)
{
int temp;
scanf("%d",&temp);
for(int j=0;j<cnt;j++)
{
if(temp%a[j]!=0)num[i][j]=num[i-1][j];
else num[i][j]=num[i-1][j]+1;
}
}
while(q--)
{
int l,r,x,res=0;
scanf("%d%d%d",&l,&r,&x);
for(int i=0;i<10;i++)
if(x&(1<<i))b[res++]=i+1;
if(b[0]==1)printf("%d\n",r-l+1);
else
{
for(int i=0;i<res;i++)
for(int j=i+1;j<res;j++)
if(b[j]%b[i]==0)
swap(b[j],b[res-1]),res--,j--;
int N=1<<res,ans=0;
for(int i=1;i<N;i++)
{
int temp=1,count=0;
for(int j=0;j<res;j++)
if(i&(1<<j))temp=lcm(temp,b[j]),count++;
if(count&1)ans+=num[r][c[temp]]-num[l-1][c[temp]];
else ans-=num[r][c[temp]]-num[l-1][c[temp]];
}
printf("%d\n",ans);
}
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: