• ZOJ 3940 Modulo Query(YY+二分)


    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.

    题目链接:ZOJ 3940

    题意:给出N个数Ai和M,又给Q个询问,每一个询问都是求[0,M]中求是否存在X使得X%A1%A2%A3%......%An=Yi,输出符合有几个这种整数X。

    可以发现任何情况下对连续的数取模除非当前值比上一个取模值小,否则直接跳过即可,当然最重要的不是这里,而是如何把题目转换一下,每一次问[0,M]中符合题意的X个数,那么我们可以把[0,M]区间分割为无数个被取模后的小区间,若计这些小区间的贡献均为1,则覆盖在点Yi的情况就是询问Yi的答案,怎么分割呢,当然是用题目给的A数组分割,顺序地输入数组,这里就可以用到上面讲到的取模的技巧来减少分割的次数,分割之后做一遍前缀或后缀和(比如小区间0-1与0-2,0-2显然是包括0-1的,因此是前缀或后缀和关系,两种不同的和只会影响统计时候的加减法问题不会影响答案)。然后询问的时候二分到第一个大于Yi的区间,假设你输入的是3,二分出来的位置是pos,pos对应的子区间为0-4,答案就是从pos~end的贡献和。因为在pos之前只会产生小于3的数,不可能出现3的情况,只有从至少%4开始,才会出现3

    代码:

    #include <bits/stdc++.h>
    using namespace std;
    #define INF 0x3f3f3f3f
    typedef pair<int, int> pii;
    typedef long long LL;
    const int N = 1e5 + 7;
    const LL MOD = 1e9 + 7;
    int A[N];
    map<int, int>pos;
    pii prefix[N << 2];
    
    inline int getpos(int l, int r, int key)
    {
        int ans = -1;
        while (l <= r)
        {
            int mid = (l + r) >> 1;
            if (prefix[mid].first > key)
            {
                ans = mid;
                r = mid - 1;
            }
            else
                l = mid + 1;
        }
        return ans;
    }
    int main(void)
    {
        int tcase, n, m, i, q;
        scanf("%d", &tcase);
        while (tcase--)
        {
            int Min = INF;
            pos.clear();
            scanf("%d%d", &n, &m);
            pos[m + 1] = 1;
            prefix[0] = {0, 0};
            for (i = 1; i <= n; ++i)
            {
                scanf("%d", &A[i]);
                if (A[i] < Min)
                    Min = A[i];
                while (1)
                {
                    auto it = pos.upper_bound(A[i]);
                    if (it == pos.end())
                        break;
                    int olde = it->first;
                    int oldcnt = it->second;
                    pos[A[i]] += olde / A[i] * oldcnt;
                    if (olde % A[i] != 0)
                        pos[olde % A[i]] += oldcnt;
                    pos.erase(it);
                }
            }
            auto it = pos.begin();
            int sz = 0;
            while (it != pos.end())
            {
                ++sz;
                prefix[sz].second = prefix[sz - 1].second + it->second;
                prefix[sz].first = it->first;
                ++it;
            }
            scanf("%d", &q);
            LL ans = 0LL;
            for (i = 1; i <= q; ++i)
            {
                LL curans;
                int x;
                scanf("%d", &x);
                if (x >= Min)
                    curans = 0LL;
                else
                {
                    int l = getpos(1, sz, x);
                    if (~l)
                        curans = prefix[sz].second - prefix[l - 1].second;
                    else
                        curans = 0LL;
                }
                if (curans)
                {
                    ans = ans + (LL)i * curans % MOD;
                    if (ans > MOD)
                        ans %= MOD;
                }
            }
            printf("%lld
    ", ans);
        }
        return 0;
    }
  • 相关阅读:
    区块链中的密码学
    初识nodeJS
    JS或jQuery获取当前屏幕宽度
    jQuery与Zepto的异同
    使用递归解决斐波那契数列的性能问题
    sass高级语法的补充
    sass的高级语法
    栅格 CSS中的循环 媒体查询
    Zepto
    dedecms 留言板中引用模板文件方法
  • 原文地址:https://www.cnblogs.com/Blackops/p/6729829.html
Copyright © 2020-2023  润新知