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

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
#include
#include
#include
#include
#include
#include
#include
#include
#include
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<1);
        a[cnt++]=temp;
    }
    sort(a,a+cnt);
    cnt=unique(a,a+cnt)-a;
    printf("cnt=%d\n",cnt); 
    for(int i=0;iint 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;jif(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<1;
            if(b[0]==1)printf("%d\n",r-l+1);
            else
            {
                for(int i=0;ifor(int j=i+1;jif(b[j]%b[i]==0)
                            swap(b[j],b[res-1]),res--,j--;
                int N=1<0;
                for(int i=1;iint temp=1,count=0;
                    for(int j=0;jif(i&(1<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;
}

你可能感兴趣的:(组合数学,数论,GYM)