zoukankan      html  css  js  c++  java
  • 南昌区域赛-G Eating Plan

    链接:https://nanti.jisuanke.com/t/42582

    Description

    Bob is hungry now and he needs to eat some food. Alice puts n* dishes of food in front of him, numbered from $1 $ to $ n$. Alice tells him that he can only eat continuous dishes of food, or he will be poisoned by food. For example, if there are 1010 dishes, he can eat the food in the 2-nd, 3-rd and 4-th dishes but he can not eat the food in the 2-nd, 3-rd and 5-th dishes because there is the 4-th dish between them so it's not continuous. Furthermore, if he chooses to eat food in the i-th dish, he has to eat all food in that dish.

    Bob's stomach has a strange feature that if there is at least t (=(998857459)) kg food in it, the weight in it will reduce t kg repeatedly until it is strictly lower than t kg. Also, if the weight of food in his stomach is exactly t kg, his stomach will be empty. Now Bob wants to eat the smallest number of dishes and remains no less than k kg food in his stomach. Can you tell him how many dishes he needs to choose?

    Input

    The first line contains two integers n and m((1leq nleq 100000,1leq mleq 10000)), indicates the number of dishes and the number of queries.

    The second line contains n integers (a_1,a_2,cdots,a_n), which is a permutation of (1, 2, cdots, n), indicates that there is ((a_i!)) kg food in the i-th dish, where (s! = 1 imes 2 imes 3 imes cdots imes s).

    The third line contains mm integers, the i-th integer (k_i(1leq k_i<t)) indicates a query with the lower bound of weight.

    Output

    Each line of mm lines contains an integer indicates the number of dishes Bob needs to choose in that query. If there is no way to reach Bob's target, output -1 instead.

    Sample Input

    4 2
    1 2 3 4
    29 31
    

    Sample out

    2
    3
    

    题意

    给定n个数,m次询问

    对于n个数,每个数的值是其阶乘值%998857459

    每次询问一个数x,问最短的连续区间的和(取模意义下)大于x,输出最短的区间长度

    题解

    这个题不难,但是细节比较多

    首先我们发现这个取模的数十分奇怪,我们对它质因数分解一下,果然,这不是个质数,它等于(461 imes 773 imes 2803),也就是说,超过2803的数,求阶乘再取模会等于0,且区间至多有2803个不同的数,我们先预处理一下区间,把所有等于0的数合并到不等于0的数上,让其区间长度+1,这样我们处理完之后的数组至多只有2803的大小,我们直接n^2暴力把所有区间和算出来,求出区间长度,对于询问二分答案即可

    这里要注意,由于我们把0合并到了它右边第一个不等于零的位置上,所以我们其实在左端点是多算了一次的,比如下面的区间(0,0,1,0,2),如果求大于等于3的区间,我们将会输出5,因为1和2所代表的区间长度分别为3和2,所以我们要减去左端的0的个数.

    此题只给了1s,如果(2803*2803*O(map))时间复杂度不够,所以我们要先全部存起来再sort取最小值,求出对应值的区间最短值,由于值越大,区间长度不一定越大,我们还需要倒序取一遍min,之后直接二分,就可以通过此题了

    代码

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N = 1e5 + 50;
    int a[N];
    const ll mod = 998857459;
    ll fac[N];
    vector<ll> b;
    vector<ll> num;
    ll pre1[N];
    ll pre2[N];
    map<ll, ll> mp;
    struct node {
        ll val, len;
        node (ll val = 0, ll len = 0): val(val), len(len) {}
        bool operator < (const node &b) const {
            if (val == b.val) {
                return len < b.len;
            }
            return val < b.val;
        }
    }tmp[2900 * 2900];
    ll val[N];
    ll len[N];
    int main() {
        int n, m;
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= n; i++) {
            scanf("%d", &a[i]);
        }
        fac[0] = 1;
        for (int i = 1; i < 2803; i++) {
            fac[i] = fac[i - 1] * i % mod;
        }
        int cnt = 0;
        for (int i = 1; i <= n; i++) {
            if (a[i] >= 2803) {
                cnt++;
            }
            else {
                num.push_back(cnt + 1);
                b.push_back(fac[a[i]]);
                cnt = 0;
            }
        }
        for (int i = 0; i < b.size(); i++) {
            pre1[i + 1] = (pre1[i] + b[i]) % mod;
            pre2[i + 1] = (pre2[i] + num[i]);
        }
        int p = 0;
        for (int i = 0; i < b.size(); i++) {
            for (int j = i; j < b.size(); j++) {
                ll now = (pre1[j + 1] - pre1[i] + mod) % mod;
                ll l = pre2[j + 1] - pre2[i] - (num[i] - 1);
                tmp[++p] = node(now, l);
            }
        }
        sort(tmp + 1, tmp + p + 1);
        cnt = 0;
        for (int i = 1; i <= p; i++) {
            if (tmp[i].val != tmp[i - 1].val || i == 1) {
                val[++cnt] = tmp[i].val;
                len[cnt] = tmp[i].len;
            }
        }
        for (int i = cnt - 1; i >= 1; i--) len[i] = min(len[i + 1], len[i]);
        while (m--) {
            int x;
            scanf("%d", &x);
            int l = 1, r = cnt;
            ll ans = 1e9;
            while (l <= r) {
                int mid = (l + r) >> 1;
                if (val[mid] >= x) {
                    ans = min(ans, len[mid]);
                    r = mid - 1;
                }
                else l = mid + 1;
            }
            if (ans == 1e9) ans = -1;
            printf("%lld
    ", ans);
        }
        return 0;
    }
    
    
  • 相关阅读:
    腾讯电脑管家创始刘钊:教你如何手撕破解一个木马
    【渗透笔记】拿下复旦大学的艰难过程
    新博客在SEO方面需要注意哪几点?
    【渗透课程】第七篇-上传漏洞之绕过上传漏洞
    【渗透课程】第八篇-上传漏洞之文本编辑器上传
    【渗透课程】第六篇-上传漏洞之解析漏洞
    【渗透课程】第五篇-SQL注入的原理
    【渗透课程】第四篇-Web安全之信息探测
    【渗透课程】第三篇-体验http协议的应用
    三星的高效会议原则
  • 原文地址:https://www.cnblogs.com/artoriax/p/12188239.html
Copyright © 2011-2022 走看看