2018湖北省赛网络赛H: GSS and OJ Submissions(分块)

版权声明:谁他喵没事儿会转我的博客啊QAQ,有没有人看都是一回事儿。。。 https://blog.csdn.net/f2935552941/article/details/79966277

题意链接:http://cdn.vo-ov.cn/online_f9ec217.pdf


题目大意:

给出如下定义式,


给你一个n n范围为4e8,根据上述的式子跑出所有的s[n],在这些所有的s[n]中求第L小的数。


解题思路:

这场比赛最后E题和H题完全没思路,还是弱啊。不过赛后听了题解之后,感觉H题应该比E题简单一些,E题用最短路的解法比赛的时候完全没想到= = 。

总之H题就是利用分块的思想,因为s数组是 ull 型的,所以我们可以认为其中最大的数就是2^64,我们直接O(n)预先跑出所有的s[n],过程中把每个数分类,分类的具体做法就是拿每个数除以一个大数,以除大数后的商分类,这样我们就可以得到商分别为0到2000000数的个数,之后我们再直接判断出第L个数应该在哪一个商所属的数该商记为k,之后重新跑一遍所有的数把商为k的数记录到一个数组,最后把这个数组排序之后直接输入第L个即可,详细的看代码吧。


Ac代码:

#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
typedef long long LL;
const int maxn=1e4+5;
const ull lv=1e14;  //这个数的大小决定了你商统计数组的大小
const LL MOD=998244353;
ull A,B,s0,s;
vector<ull> v;
int n,l,num[2000005];
int main()
{
    while(scanf("%llu%llu%d%d%llu",&A,&B,&l,&n,&s0)!=EOF)
    {
        num[s0/lv]++;
        s=s0;
        for(int i=1;i<n;i++)
        {
            s0=s0*A+B;
            num[s0/lv]++;   //记录商对应的数的个数
        }
        int pos=0;
        for(int i=0;i<2000000;i++)  //统计L应在哪个范围
        {
            if(l>num[i]) l-=num[i];
            else
            {
                pos=i;
                break;
            }
        }
        for(int i=1;i<=n;i++)   //将商为pos的数记录下来
        {
            if(s/lv==pos) v.push_back(s);
            s=s*A+B;
        }
        sort(v.begin(),v.end());    //排序得出结果
        printf("%llu\n",v[l-1]);
    }
}



阅读更多
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页