zoukankan      html  css  js  c++  java
  • 7375. 【2021.11.11NOIP提高组联考】叁仟柒佰万

    Description

    给定一个序列 (a) ,你需要把它划分成任意多段,满足任意一段的 (mex) 值相同,求方案数,对 (10^{9}+7) 取模。

    定义一个区间的 (mex) 为区间中最小的没有出现过的自然数。

    (1le nle 37000000)

    Solution

    首先有个结论,就是最后划分的各个区间的 (mex) 跟整个区间的 (mex) 是一样的。

    证明:

    令全局 (mex)(K), 则说明 (0 sim K-1) 的数都存在于数列中而 (K) 不存在。

    假设我们最后每个区间的 (mex) 均为 (X)

    (X<K), 由于序列中为 (X) 的数存在, (X) 必定在其中一个区间中, 与所有区间 (mex=X) 矛盾。

    (X>K), 由于不存在 (K), 显然不合法。

    于是只能是 (X=K)

    知道了这个结论,( ext{dp}) 转移式子就好搞了。

    (f_i) 表示到 (i) 结尾的方案数,转移方程:

    (f_i=sum_{1le j<i} f_j[get(j,i)=mex])(令 (get(j,i)) 表示区间 (jsim i)(mex))。

    注意到 (get(j,i)) 在某个 (j) 使得 (get(j,i)=mex) 后,保持不变。

    因此我们只需要在 (mathcal{O}(n)) 的时间里求出 (j),然后用前缀和更新答案。

    至于求出 (j),可以使用桶来处理。


    题外话:至于 (n) 的范围为什么是 37000000,原因如下:

    题目背景:当年陈刀仔,他用 20 块贏到三千七百万,今天我也要从 (n=10) 出到 (n=37000000) !

    Code

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define mod 1000000007
    #define N 37000005
    using namespace std;
    int T,n,x,y,mex,ans,num,now,fs,a[N],sum[N],near[N];
    bool flag,t[N];
    int getmex()
    {
    	int res=0;
    	while (t[res]) ++res;
    	return res;
    }
    int main()
    {
    	freopen("clods.in","r",stdin);
    	freopen("clods.out","w",stdout);
    	scanf("%d",&T);
    	while (T--)
    	{
    		scanf("%d",&n);
    		mex=0;num=0;
    		if (n!=37000000)
    			for (int i=1;i<=n;++i)
    				scanf("%d",&a[i]);
    		else
    		{
    			scanf("%d%d",&x,&y);
    			for (int i=2;i<=n;++i)
    				a[i]=(a[i-1]*x+y+i)&262143;
    		}
    		for (int i=0;i<=n;++i)
    			t[i]=0;
    		for (int i=1;i<=n;++i)
    			t[a[i]]=1;
    		mex=getmex();
    		if (mex==0)
    		{
    			ans=1;
    			for (int i=1;i<n;++i)
    				ans=ans*2%mod;
    			printf("%d
    ",ans);
    			continue;
    		}
    		for (int i=0;i<mex;++i)
    			t[i]=0,near[i]=-1;
    		for (int i=1;i<=n;++i)
    			if (a[i]<mex)
    			{
    				if (!t[a[i]]) t[a[i]]=1,++num;
    				if (num==mex)
    				{
    					fs=i;
    					break;
    				}
    			}
    		for (int i=0;i<=n;++i)
    			t[i]=0,sum[i]=0;
    		flag=false;now=1;ans=0;
    		for (int i=1;i<=n;++i)
    		{
    			if (a[i]<mex)
    			{
    				if (near[a[i]]!=-1) t[near[a[i]]]=0;
    				near[a[i]]=i;
    				t[i]=1;
    			}
    			if (i==fs) flag=true;
    			while (flag&&!t[now]) ++now;
    			if (flag) ans=sum[now-1]+1;
    			if (ans==mod) ans=0;
    			sum[i]=(sum[i-1]+ans)%mod;
    		}
    		printf("%d
    ",ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    修复PLSQL Developer 与 Office 2010的集成导出Excel 功能
    Using svn in CLI with Batch
    mysql 备份数据库 mysqldump
    Red Hat 5.8 CentOS 6.5 共用 输入法
    HP 4411s Install Red Hat Enterprise Linux 5.8) Wireless Driver
    变更RHEL(Red Hat Enterprise Linux 5.8)更新源使之自动更新
    RedHat 5.6 问题简记
    Weblogic 9.2和10.3 改密码 一站完成
    ExtJS Tab里放Grid高度自适应问题,官方Perfect方案。
    文件和目录之utime函数
  • 原文地址:https://www.cnblogs.com/Livingston/p/15540584.html
Copyright © 2011-2022 走看看