首页 > 其他分享 >题解 P8757 [蓝桥杯 2021 省 A2] 完美序列

题解 P8757 [蓝桥杯 2021 省 A2] 完美序列

时间:2023-06-30 10:25:28浏览次数:56  
标签:int 题解 len 蓝桥 完美 A2 替换成 ans 序列

题解 P8757 [蓝桥杯 2021 省 A2] 完美序列

题意

如果一个序列是单调递减的,而且除了第一个数以外的任何一个数都是上一个数的因数,则称这个序列为一个完美序列。

一个序列中的一个子序列如果是完美序列,则称为该序列的一个完美子序列。一个序列的最长完美子序列长度,称为该序列的完美长度。

给定正整数 \(n\),\(1\) 至 \(n\) 的所有排列的完美长度的最大值,称为 \(n\) 阶最大完美长度。

给定正整数 \(n\),请求出 \(1\) 至 \(n\) 的所有排列中长度正好为 \(n\) 阶最大完美长度的所有完美子序列的价值的和。

思路

显然地,\(n\) 阶最大完美长度 \(len=\lfloor\log_2n\rfloor+1\),因为从 \(highbit(n)\) 开始,每次除 \(2\) 一定不会更劣。

考虑如何证明。考虑每次除的数,构成了一个长为 \(len-1\) 的序列。

  1. 如果替换掉一个数。显然只可能替换成质数。
    如果 \(n\ge\frac{3}{2}highbit(n)\),那么可以将序列中的一位替换成 \(3\),此时最大完美长度不变。
    如果替换成 \(5\),显然 \(n<\frac{5}{2}highbit(n)\)。这样最大位就比 \(n\) 大了,肯定是不行的。
    大于 \(5\) 的数同理。
    因此,只可能把序列中的某位替换成 \(3\)。
  2. 如果替换掉多个数。还是值可能替换成质数。
    如果替换两个 \(3\),显然 \(n<\frac{9}{4}highbit(n)\)。这样最大位就比 \(n\) 大了,肯定不行。
    显然,如果替换成更大或者更多的数,也一定不行。

在这个过程中,我们发现,这个序列中,只可能有 \(2\) 和 \(3\),而且最多只会有一个 \(3\)。

考虑计算每个数可以贡献多少次。假设现在是从小到大的第 \(i\) 个数,这个数为 \(x\)。

首先,要在 \(n\) 个位置中选 \(len\) 个位置作为完美序列,剩下的 \(n-len\) 个位置随便排,这部分是 \(\binom{n}{len}\times(n-len)!\)。

现在排列的位置确定了,考虑有多少种排列会让 \(x\) 产生贡献。

  1. 如果 \(x\) 的因子中没有 \(3\),那么如果 \(n\ge\frac{3}{2}highbit(n)\),则有 \(len-i\) 个位置可以被替换成 \(3\)。
    再加上全部是 \(2\) 的一种,总共就是 \(1+[可以有3](n-len)\) 种。
  2. 如果 \(x\) 的因子中有 \(3\),那么有 \(i\) 个位置可以放 \(3\)。
    总共就是 \([可以有3]len\) 种。

枚举即可,复杂度 \(O(n\log n+n\log P)\)。

#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read(){
	int ans=0;bool op=0;char ch=getchar();
	while(ch<'0'||'9'<ch){if(ch=='-')op=1;ch=getchar();}
	while('0'<=ch&&ch<='9'){ans=(ans<<1)+(ans<<3)+(ch^48);ch=getchar();}
	if(op)return -ans;
	return ans;
}
const int maxn=1e6+10;
const int mod=1e9+7;
int n;
int fact[maxn];
int ifac[maxn];
int len;
int base;
int ans=0;
int inv(int a){
	int ans=1;
	for(int i=mod-2;i;i>>=1){
		if(i&1)ans=ans*a%mod;
		a=a*a%mod;
	}
	return ans;
}
int C(int a,int b){
	if(b>a||a<0||b<0)return 0;
	return fact[a]*ifac[b]%mod*ifac[a-b]%mod;
}
void real_main(){
	n=read();
	if(n==1){
		puts("1");
		return;
	}
	len=__lg(n)+1;
	base=1;
	ans=0;
	for(int i=1;i<=len;i++){//只有2的
		ans=(ans+C(n,len)*base%mod*fact[n-len]%mod)%mod;
		base<<=1;
	}
	if((1<<(len-2))*3>n){
		cout<<ans<<'\n';
		return;
	}
	base=1;
	for(int i=1;i<=len;i++){//不含3的
		ans+=C(n,len)*base*(len-i)%mod*fact[n-len]%mod;
		ans%=mod;
		base<<=1;
	}
	base=3;
	for(int i=2;i<=len;i++){//含3的
		ans+=C(n,len)*base*(i-1)%mod*fact[n-len]%mod;
		ans%=mod;
		base<<=1;
	}
	cout<<ans<<'\n';
}
signed main(){
	fact[0]=1;
	for(int i=1;i<maxn;i++)fact[i]=fact[i-1]*i%mod;
	for(int i=0;i<maxn;i++)ifac[i]=inv(fact[i]);
	int T=read();
	while(T--)real_main();
	return 0;
}

优化

这样已经可以过了,但是还可以优化一下。

容易发现,每个式子都含有C(n,len)*fact[n-len]

定义 \(tot=\binom{n}{len}*(n-len)!\),即可避免预处理逆元。

或者,容易发现,\(\binom{n}{len}\times(n-len)!=\frac{n!}{len!}\),而 \(len=\lfloor\log_2n\rfloor+1\)。所以只要预处理出前 \(20\) 个阶乘的逆元即可。

观察全 \(2\),除了 \(tot\) 之外的部分等于 \(\sum_{i=1}^{len}2^{i-1}=\sum_{i=0}^{len-1}2^i=2^{len}-1\)。

观察不含 \(3\),除了 \(tot\) 之外的部分:

\[\begin{align} &f(len)\nonumber\\ =&\sum_{i=1}^len2^{i-1}(len-i)\nonumber\\ =&\sum_{i=1}^{len-1}2^{i-1}(len-1-i+1)\nonumber\\ =&\sum_{i=1}^{len-1}2^{i-1}(len-1-i)+\sum_{i=1}^{len-1}2^{i-1}\nonumber\\ =&f(len-1)+\sum_{i=0}^{len-2}2^i\nonumber\\ =&f(len-1)+2^{len-1}-1\nonumber\\ \end{align} \]

观察含 \(3\),除了 \(tot\) 之外的部分 \(g(len)=g(len-1)+base\times(len-1)\)。\(base\) 的含义见上面的代码。

现在,我们把每一个计算都优化成了递推,可以预处理。单次询问 \(O(1)\)。

复杂度 \(O(T+\log_2n)\),卡到了本题最优解(2023.6.30)。

提交记录

@TQI_II为机房公用账号,上面也是我交的,会在下面发个评论证明一下。

#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read(){
	int ans=0;bool op=0;char ch=getchar();
	while(ch<'0'||'9'<ch){if(ch=='-')op=1;ch=getchar();}
	while('0'<=ch&&ch<='9'){ans=(ans<<1)+(ans<<3)+(ch^48);ch=getchar();}
	if(op)return -ans;
	return ans;
}
const int maxn=1e6+10;
const int mod=1e9+7;
int n;
int fact[maxn];
int ifac[maxn];
int len;
int base;
int ans=0;
int pre2[maxn];
int pre23[maxn];
int pre33[maxn];
int inv(int a){
	int ans=1;
	for(int i=mod-2;i;i>>=1){
		if(i&1)ans=ans*a%mod;
		a=a*a%mod;
	}
	return ans;
}
signed main(){
	fact[0]=1;
	for(int i=1;i<maxn;i++)fact[i]=fact[i-1]*i%mod;
	ifac[20]=inv(fact[20]);
    for (int i=19;i>=0;i--)ifac[i]=(ifac[i+1]*(i+1))%mod;
	base=1;
	for(int i=1;(1<<(i-1))<maxn;i++){
		pre2[i]=(pre2[i-1]+base)%mod;
		pre23[i]=(pre23[i-1]+base-1)%mod;
		base<<=1;
	}
	base=3;
	for(int i=2;(1<<(i-1))<maxn;i++){
		pre33[i]=(pre33[i-1]+base*(i-1))%mod;
		base<<=1;
	}
	int T=read();
	while(T--){
		n=read();
		if(n==1){
			puts("1");
			continue;;
		}
		len=__lg(n)+1,ans=0;
		int tot=fact[n]*ifac[len]%mod;
		ans=(ans+pre2[len]*tot%mod)%mod;
		if((1<<(len-2))*3>n)cout<<ans<<'\n';
		else cout<<(ans+tot*(pre23[len]+pre33[len])%mod)%mod<<'\n';
	}
	return 0;
}

标签:int,题解,len,蓝桥,完美,A2,替换成,ans,序列
From: https://www.cnblogs.com/Augury/p/17515872.html

相关文章

  • DLL-FILES.COM - 您的DLL问题解决方案!--九五小庞
    每个人都遇到过“无法找到****.dll文件...”的消息弹窗。各位,这个问题终于可以解决了!在这里你可以找到电脑上最常丢失或损坏的文件。自由下载,无任何费用! ......
  • AT_arc067_f 题解
    传送门Simplify不难想到其实题意就是让你求:\[\max_{1\lel\ler\len}\left\{\sum_{i=1}^m\max_{l\lej\ler}\{b_{i,j}\}-\sum_{i=l}^ra_i\right\}\]Solution首先考虑暴力,我的话是枚举\(l,r(l\in[1,n],l\in[1,r])\),然后\(m\)个单调队列先把\(l\)到\(r\)的b数组存进......
  • 台达A2 B2伺服电机编码器改功率软件 台达A2 B2伺服电机编码修改
    台达A2B2伺服电机编码器改功率软件台达A2B2伺服电机编码修改,用于更换编码器写匹配电机参数,更改编码器功率匹配驱动器测试维修用"台达A2B2伺服电机编码器改功率软件"是一款用于修改台达A2B2型号的伺服电机编码器的软件。它的主要功能是更换编码器并编写匹配的电机参数,以及修改......
  • ABC143F 题解
    前言题目传送门!更好的阅读体验?很有趣的题。提供一种和现有题解略微不同的做法。思路突破点在于反着想。当最多能取\(x\)次时,每次我取的不同数字的数量,最多是多少。统计一下每个数字出现的次数\(cnt_i\)。那么这个最多次数应为\[\left\lfloor\dfrac{\sum\min(cnt_i,x)}x......
  • 「ARC133E」Cyclic Medians 题解
    本文网址:https://www.cnblogs.com/zsc985246/p/17513317.html,转载请注明出处。传送门「ARC133E」CyclicMedians题目大意给定\(n,m,V,A\),你需要计算所有长为\(n\)、值域为\([1,V]\)的整数序列\(x\)和长为\(m\)、值域为\([1,V]\)的整数序列\(y\)形成的序列对\((x_......
  • ZB5AA26 Schneider Electric 芯脉芯城
    ZB5AA26是一个产品型号,通常用于指示灯或按钮开关。以下是关于ZB5AA26的一些常见参数:封装类型:ZB5AA26采用的是标准的按钮开关封装。动作类型:ZB5AA26是一个单极单刀按钮开关,即具有一个触点和一个开关位置。额定电压:ZB5AA26的额定电压通常为24V,适用于直流或交流电源。额定电流:ZB5AA26......
  • Codeforces[CF1036B]Diagonal Walking v.2题解
    题目大意很明显,这道题就是求k步之内到达点\((a,b)\),然后尽量走对角线,求能走对角线的最大值。做题思路首先明白一个事实,即一个对角线可以通过增加一步而抵达点不变,如图:我们可以这样思考这道题,在到达目的地以后,剩余步数如果为双数,则在对角线来回走,最后会到目的地。但如果剩......
  • Switches and Lamps 题解
    题目传送门一道枚举题。首先我们需要知道什么开关才能被去掉,题目要求去掉这个开关后所有的灯依然能够开启。也就是说,这个开关能打开的所有灯都可以由其它开关代替。思路清晰了,就比较好做。我们可以用一个数组存储下每一盏灯可以被几个开关开启,如果有一盏灯只能被\(1\)个开关......
  • P1552 [APIO2012] 派遣 题解
    一、题目描述:给你一个$n$个点的有根树,每个点有两个参数$w$和$v$。再给出一个数$m$。对于每一个点$u$,设它的子树内最多可以选择$k_u$个点$a_1,a_2,...,a_{k_u}$,使得$\sum_{i=1}^kw_{a_i}\lem$。那么点$u$的价值为$v_u\timesk_u$,求$max(\su......
  • 前端打包部署后接口BASE_URL不对问题解决办法
    在前端打包部署时,为了免去不同环境打包的麻烦,项目用的流水线触发方式。在这里不细说,重点说说下面情况。当项目提交打包部署后,访问压测环境或者生产环境的地址来使用项目时,发现接口报错404。 在NETWORK里发现接口的BASEURL和当前环境需要调用的后端baseurl不同。主要问题在于......