ZOJ 3940 Modulo Query(区间取模)

本文介绍了一种解决特定模运算问题的高效算法,通过构造优先队列和区间更新的方法,实现了对一系列模运算的快速求解。适用于处理大规模数据集上的模运算问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Modulo Query

Time Limit: 2 Seconds      Memory Limit: 65536 KB

One day, Peter came across a function which looks like:

  • F(1, X) = X mod A1.
  • F(iX) = F(i - 1, X) mod Ai, 2 ≤ i ≤ N.
Where A is an integer array of length NX is a non-negative integer no greater than M.

Peter wants to know the number of solutions for equation F(NX) = Y, where Y is a given number.

Input

There are multiple test cases. The first line of input contains an integer T, indicating the number of test cases. For each test case:

The first line contains two integers N and M (2 ≤ N ≤ 105, 0 ≤ M ≤ 109).

The second line contains N integers: A1A2, ..., AN (1 ≤ Ai ≤ 109).

The third line contains an integer Q (1 ≤ Q ≤ 105) - the number of queries. Each of the following Q lines contains an integer Yi (0 ≤ Yi ≤ 109), which means Peter wants to know the number of solutions for equation F(NX) = Yi.

Output

For each test cases, output an integer S = (1 ⋅ Z1 + 2 ⋅ Z2 + ... + Q ⋅ ZQ) mod (109 + 7), where Zi is the answer for the i-th query.

Sample Input
1
3 5
3 2 4
5
0
1
2
3
4
Sample Output
8
Hint

The answer for each query is: 4, 2, 0, 0, 0.

题解:
整个区间n个数取模,因为每个数取模后至少变为原来的二分之一,因此复杂度n*logn
node right表示区间的最右端点,cnt表示此区间的个数
代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=1e5+7;
const int mod=1e9+7;
int n,m,t[maxn],rr[maxn];
struct node
{
    int right,cnt;
}c[maxn];
bool operator<(const node &a,const node &b)
{
    return a.right<b.right;
}
bool cmp(const node &a,const node &b)
{
    return a.right<b.right;
}
int main()
{
    int T;scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);
        priority_queue<node>P;
        node r;r.right=m,r.cnt=1;
        P.push(r);
        for(int i=0;i<n;i++)
        {
            int x;scanf("%d",&x);
            while(P.top().right>=x)
            {
                node e=P.top();P.pop();
                int cnt=e.cnt;
                while(!P.empty()&&P.top().right==e.right)
                    cnt+=P.top().cnt,P.pop();
                r.right=x-1,r.cnt=(e.right+1)/x*cnt;
                P.push(r);
                if((e.right+1)%x)
                {
                    r.right=e.right%x;r.cnt=cnt;
                    P.push(r);
                }
            }
        }
        int tol=0;
        while(!P.empty())
        {
            c[tol].cnt=P.top().cnt;
            c[tol++].right=P.top().right;
            P.pop();
        }
        ll ans=0,Q;scanf("%lld",&Q);
        sort(c,c+tol,cmp);
        memset(t,0,sizeof(t));
        t[tol-1]=c[tol-1].cnt;rr[tol-1]=c[tol-1].right;
        for(int i=tol-2;i>=0;i--)t[i]=t[i+1]+c[i].cnt,rr[i]=c[i].right;
        for(ll i=1;i<=Q;i++)
        {
            int x;scanf("%d",&x);
            int id=lower_bound(rr,rr+tol,x)-rr;
            ans=(ans+1LL*t[id]*i)%mod;
        }
        printf("%lld\n",ans);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值