Modulo Query ZOJ - 3940 (区间取模)

题目

https://cn.vjudge.net/problem/ZOJ-3940

题意

给你n个模数,和一个0-m范围,Q次询问,每次问范围内有多少数结果是给定的数

思路

区间取模,对x个区间取模,最多会产生x+1个区间,即x个0-(x-1)的区间合并为一个,和0-(

所有最后最多会有2*n个区间,

对于所有的查询x,查找有多少区间又端点大于等于x,即答案

代码

#include
using namespace std;
#define ll long long
const ll mod = 1e9+7;
struct node
{
    int r,cnt;
    bool operator < (const node &a) const
    {
        return r < a.r;
    }
}a[500005];
int sum[500005];
int qw[500005];
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n,m;
        scanf("%d%d",&n,&m);
        node u;
        u.r = m,u.cnt = 1;
        priority_queue q;
        q.push(u);
        for(int i = 1;i <= n;i++)
        {
            int x;
            scanf("%d",&x);
            while(q.top().r >= x)
            {
                u = q.top();
                q.pop();
                int cnt = u.cnt;
                while(!q.empty()&&q.top().r == u.r)
                {
                    cnt+=q.top().cnt;
                    q.pop();
                }
                node v;
                v.r = x - 1;
                int num = cnt*(u.r/x);
                v.cnt = num;
                q.push(v);
                v.r = u.r % x;
                v.cnt = cnt;
                q.push(v);
            }
        }
        int p = 0;
        while(!q.empty())
        {
            a[p].r = q.top().r;
            a[p++].cnt = q.top().cnt;
            q.pop();
        }
        sort(a,a+p);
        memset(sum,0,sizeof(sum));
        for(int i =p-1;i >= 0;i--)
        {
            sum[i] = sum[i+1] + a[i].cnt;
            qw[i] = a[i].r;
        }
        int Q;
        scanf("%d",&Q);
        ll ans = 0;
        for(int k = 1;k <= Q;k++)
        {
            int x;
            scanf("%d",&x);
            int id = lower_bound(qw,qw+p,x) - qw;
            ans += (ll)k*sum[id];
            ans %= mod;
        }
        printf("%lld\n",ans);
    }
    return 0;
}

 

你可能感兴趣的:(数论)