[codechef MEXDIV]Mex division

直接用set+dp水过去了。。。

/*
设dp[i]表示前i个做划分满足条件的方案数
有一个显然的转移方程dp[i]=sigma(dp[j])  t<=j<=i-1
其中t是满足mex(a[t..i-1])<=k的最小的t
然后我们现在是想得到,对于每个位置这个t是多少,如果知道了这个,就可以很容易的转移了

首先,考虑,如果k>n,那么不管怎么选,都是会满足条件的啊!(就算把所有的数都选出来,mex也就是k吧)
所以对于k>n,直接输出2^(n-1)当然k=0的时候特判一下,这样每个i对应的t都是存在的,至少有一个i

现在考虑k<=n的情况,直接用一个multiset记录[1,k]里的数的出现情况
首先,把[0,k]全部都放进multiset,遇到一个新的数,就erase,查询集合里最小的数就是mex 

假设现在想得到第i个位置的t,上次求得的i-1对应的t是t‘
那么如果a[i]已经在集合中被删去了,那这次对应的肯定还是t‘
如果a[i]没有从集合中删去,就把a[i]从集合中删去(当然,如果a[i]>k直接不用管)
考虑到随着i的增大,t肯定是往右走的
如果删去以后集合是空集了,那t‘就需要右移了,直到出现一个[0,k]之间的,并且在a[t+1..i]没有出现过的数
是否出现过,只需要记一个右边第一个跟它相等的数就可以了
*/

#include<bits/stdc++.h>
using namespace std;

const int maxn=500005;
int a[maxn];
int t[maxn];
int e[maxn];
long long dp[maxn];
long long predp[maxn];
pair<int,int> p[maxn];
set<int> S;

const long long md=1000000007;
long long fp(long long a,long long k)
{
    long long res=1;
    a%=md;
    while(k)
    {
        if(k&1)res=res*a%md;
        a=a*a%md;
        k>>=1;
    }
    return res;
}

int main()
{
    int n,k;
    scanf("%d%d",&n,&k);
    for (int i=1;i<=n;i++) scanf("%d",&a[i]);
    if (k>n)
    {
        printf("%lld",fp(2,n-1));
        return 0;
    }
    if (k==0)
    {
        bool yl=false;
        for (int i=1;i<=n;i++)
        {
            if (a[i]==0)
            {
                yl=true;
                break;
            }
        }
        if (yl) printf("0\n");
        else printf("%lld",fp(2,n-1));
        return 0;
    }
    S.clear();
    for (int i=0;i<=k;i++) S.insert(i);
    for (int i=1;i<=n;i++)
    {
        p[i].first=a[i];
        p[i].second=i;
    }
    sort(p+1,p+1+n);
    p[n+1].first=-1;
    for (int i=1;i<=n;i++)
    {
        if (p[i+1].first==p[i].first) e[p[i].second]=p[i+1].second;
        else e[p[i].second]=-1;
    }
    int now=1;
    t[1]=1;
    if (a[1]<=k) S.erase(a[1]);
    for (int i=2;i<=n;i++)
    {
        if (a[i]>k || !S.count(a[i])) t[i]=t[i-1];
        else
        {
            S.erase(a[i]);
            while (S.empty())
            {
                if (a[now]<=k && (e[now]==-1||e[now]>i))
                {
                    S.insert(a[now]);
                }
                now++;
            }
            t[i]=now;
        }
    }
    dp[0]=1;
    predp[0]=0;
    predp[1]=1;
    for (int i=1;i<=n;i++)
    {
        // dp[t[i]-1]...dp[i-1]
        dp[i]=((predp[i]-predp[t[i]-1])%md+md)%md;
        predp[i+1]=(predp[i]+dp[i])%md;
    }
    printf("%lld\n",dp[n]);
    return 0;
}
时间: 2024-10-12 21:44:20

[codechef MEXDIV]Mex division的相关文章

codechef September Challenge 2018 Division 2 A-F

比赛链接 上紫啦hhh,好开心 每个题里面都有中文翻译,我就不说题意了.. A 直接模拟即可 #include<cstdio> #include<algorithm> #define int long long using namespace std; const int MAXN = 1e5 + 10; inline int read() { char c = getchar(); int x = 0, f = 1; while(c < '0' || c > '9')

codechef 营养题 第一弹

第一弾が始まる! 定期更新しない! 来源:http://wenku.baidu.com/link?url=XOJLwfgMsZp_9nhAK15591XFRgZl7f7_x7wtZ5_3T2peHh5XXoERDanUcdxw08SmRj1a5VY1o7jpW1xYv_V1kuYao1Pg4yKdfG4MfNsNAEa codechef problems 第一弹 一.Authentication Failed原题题面Several days ago Chef decided to registe

light oj 1214 - Large Division

1214 - Large Division   PDF (English) Statistics Forum Time Limit: 1 second(s) Memory Limit: 32 MB Given two integers, a and b, you should check whether a is divisible by b or not. We know that an integer a is divisible by an integer b if and only if

fzuoj1607Greedy division

题目链接: 点我点我 题目:  Problem 1607 Greedy division Accept: 436    Submit: 1590 Time Limit: 1000 mSec    Memory Limit : 32768 KB  Problem Description Oaiei has inherited a large sum of wealth recently; this treasure has n pieces of golden coins. Unfortunate

[BZOJ3585][BZOJ3339]mex

试题描述 有一个长度为n的数组{a1,a2,...,an}.m次询问,每次询问一个区间内最小没有出现过的自然数. 输入 第一行n,m.第二行为n个数.从第三行开始,每行一个询问l,r. 输出 一行一个数,表示每个询问的答案. 输入示例 5 5 2 1 0 2 1 3 3 2 3 2 4 1 2 3 5 输出示例 1 2 3 0 3 数据规模及约定 对于100%的数据:1<=n,m<=2000000<=ai<=1091<=l<=r<=n 题解 首先离线,将询问按右端

CodeChef FNCS (分块+树状数组)

题目:https://www.codechef.com/problems/FNCS 题解: 我们知道要求区间和的时候,我们用前缀和去优化.这里也是一样,我们要求第 l 个函数到第 r 个函数 [l, r] 的函数和,那么我们可以用 sum[r] - sum[l-1] 来求得. 由于这个数据量有点大,所以我们将函数分块. 例如样例: 1 3 有5个函数,那么我们分成3块.{ [1 3] , [2 5] }, { [4 5], [3 5] }, { [1 2] }.每一块对应都有一个sum ,这时如

codechef营养题 第三弹

第三弾が始まる! codechef problems 第三弹 一.Motorbike Racing 题面 It's time for the annual exciting Motorbike Race in Byteland. There are N motorcyclists taking part in the competition. Johnny is watching the race. At the present moment (time 0), Johnny has taken

matlab-bgl 工具包配置环境 TDM-GCC-64 mex

Windows 64 + Matlab 64 MEX混合编程初步: http://blog.csdn.net/enjoyyl/article/details/46545263 使用的是 TDM-GCCgccg For Matlab 2015 TDM-GCC-64 来自 51CTO下载-tdm64-gcc-4.9.2-3.zip matlab-bgl工具包下载: http://www.pudn.com/downloads737/sourcecode/math/detail2943220.html

HDU #4747 MEX

题目描述: 定义 mex(i, j) 为序列中第 i 项到第 j 项中没有出现的最小自然数.给定序列,求 Σ1≤i,j≤n,i≤j mex(i, j). 解题思路: 首先我们可以 O(n) 预处理出 mex(1, 1 ~ n),因为显然的是mex是递增的.然后我们考虑怎么从 mex(i, i ~ n) 推出 mex(i + 1, i + 1 ~ n),我们删掉 a[i] 这个数后,哪些区间的mex会改变呢?其实就是到下一个a[i]出现前mex大于a[i]的区间,因为这段区间没有了a[i]这个数,