zoukankan      html  css  js  c++  java
  • NOIP模拟赛(by hzwer) T2 小奇的序列

    【题目背景】

      小奇总是在数学课上思考奇怪的问题。

    【问题描述】

      给定一个长度为 n 的数列,以及 m 次询问,每次给出三个数 l,r 和 P, 询问 (a[l'] + a[l'+1] + ... + a[r']) mod P 的最小值。 其中 l <= l' <= r' <= r。

      即模意义下的区间子串和最小值。

    【输入格式】

      第一行包含两个正整数 n 和 m,表示数列的长度和询问的个数。

      第二行为 n 个整数,为 a[1]..a[n]。

      接下来 m 行,每行三个数 l,r 和 P,代表一次询问。

    【输出格式】

      对于每次询问,输出一行一个整数表示要求的结果

    【样例输入】

      4 2

      8 15 9 9

      1 3 10

      1 4 17

    【样例输出】

      2

      1

    【数据范围】

      对于 20%的数据 n<=100,m<=100,p<=200

      对于 40%的数据 n<=200,m<=1000,p<=500

      对于 70%的数据 n<=100000,m<=10000,p<=200

      对于 100%的数据 n<=500000,m<=10000,p<=500,1<=a[i]<=10^9

    【解析】

      这道题第一眼看过去好像没什么思路。从部分分入手吧。

      20分:直接暴力枚举每一个区间里的点,然后求最小值即可。

      40分:可以使用前缀和优化,然后就可以很快地求一个区间里的和。

      70分:假如数据是绝对随机,那么如果一个区间的长度大于p,该区间中一定可以组合出所有区间和%p的余数。其中一定会有余数为0的情况,输出0即可。经过实测,这种方法可以拿90分。

      100分:将前缀和改为区间前缀和,那么设i为当前枚举到的点,那么区间[ l , i ]的余数sum[i]=(sum[i-1]+a[i])%p。记vis[i]表示余数为i的情况在前面是否出现过。对于每一个sum[i],我们都枚举比他小的余数(从sum[i]到0,用j表示),如果vis[j]=1,表示有这种情况。假设余数为j的位置为p,那么由模运算的性质可得:区间[ p , i ]的余数为sum[i]-j。(为什么大于sum[i]的不需要?因为这不可能是更优的解)然后,用sum[i]-j去更新答案。由于余数是从大到小枚举的,且j越大sum[i]-j越小,即该区间余数越小,如果当前能够被更新,后面的就不会再对答案造成影响了,直接break即可。最后把vis[sum[i]]设为1。注意,如果当前答案已经为0了,就直接输出(不会再更优了)。另外,不要每次都去清空前缀和数组,只需要把sum[l-1]设为0即可。

    【备注】

      这道题的正解其实是平衡树,但我并不会这个东西......

    【代码】

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #define N 500002
    using namespace std;
    int n,m,a[N],l,r,p,i,j,k;
    long long sum[N];
    bool e[500002];
    long long read()
    {
        char c=getchar();
        long long w=0;
        while(c<'0'||c>'9') c=getchar();
        while(c<='9'&&c>='0'){
            w=w*10+c-'0';
            c=getchar();
        }
        return w;
    }
    long long min(long long a,long long b)
    {
        if(a<b) return a;
        return b;
    }
    int main()
    {
        freopen("seq.in","r",stdin);
        freopen("seq.out","w",stdout);
        n=read();
        m=read();
        for(i=1;i<=n;i++) a[i]=read();
        while(m--){
            l=read();
            r=read();
            p=read();
            if(r-l+1>p){
                cout<<"0"<<endl;
                continue;
            }
            for(i=1;i<=p;i++) e[i]=0;
            e[0]=1;
            sum[l-1]=0;
            long long ans=1<<30;
            for(i=l;i<=r;i++){
                sum[i]=(sum[i-1]+a[i])%p;
                for(j=sum[i];j>=0;j--){
                    if(e[j]){
                        ans=min(ans,sum[i]-j);
                        break;
                    }
                }
                if(ans==0) break;
                e[sum[i]]=1;
            }
            printf("%lld
    ",ans);
        }
        fclose(stdin);
        fclose(stdout);
        return 0;
    }
  • 相关阅读:
    Representation Data in OpenCascade BRep
    Render OpenCascade Geometry Surfaces in OpenSceneGraph
    Render OpenCascade Geometry Curves in OpenSceneGraph
    OpenCascade Shape Representation in OpenSceneGraph
    Geometry Surface of OpenCascade BRep
    Geometry Curve of OpenCascade BRep
    Tyvj2017清北冬令营入学测试
    Spfa算法模板
    洛谷1016 旅行家的预算
    洛谷1290 欧几里得的游戏
  • 原文地址:https://www.cnblogs.com/LSlzf/p/10393135.html
Copyright © 2011-2022 走看看