ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【CF1601F】Two Sorts(Meet in Middle)

2022-03-08 19:34:33  阅读:174  来源: 互联网

标签:lfloor frac rfloor CF1601F Meet Sorts mod operatorname define


题目链接

  • 定义 \(a_{1\sim n}\) 为将 \(1\sim n\) 按字典序从小到大排序后的结果,求 \((\sum_{i=1}^n(i-a_i)\ \operatorname{mod}\ 998244353)\ \operatorname{mod}\ 10^9+7\)。
  • \(1\le n\le10^{12}\)

题意转化

这题的求和中有两种不同的取模,看起来非常麻烦。

考虑取模的一个经典转化,即 \(x\ \operatorname{mod}\ y=x-\lfloor\frac xy\rfloor\times y\)。

所以原式可以写成:\((\sum_{i=1}^ni-a_i-\lfloor\frac{i-a_i}{998244353}\rfloor\times998244353)\ \operatorname{mod}\ 10^9+7\)。

发现 \(\sum i-a_i=0\),所以要求的就是 \(\sum_{i=1}^n\lfloor\frac{i-a_i}{998244353}\rfloor\)。

Meet in Middle

考虑 Meet in Middle,枚举最高的 \(6\) 位,则最高 \(6\) 位为枚举值的数肯定在 \(a\) 中是连续的一段。

对于一个长度为 \(6+l\)、较低位在所有可能的较低位中字典序排名为 \(rk\) 的数 \(y\),假设前 \(6\) 位数为 \(x\)、前 \(6\) 位小于 \(x\) 的数共有 \(ct\) 个,则它产生的贡献应该是 \(\lfloor\frac{(ct+rk)-(x10^l+y)}{998244353}\rfloor\),可以拆成只与前 \(6\) 位和 \(l\) 有关的 \(ct-x10^l\) 以及只与较低位有关的 \(rk-y\)。

形如 \(\lfloor\frac{A+B}C\rfloor\) 的式子有个经典拆分方式:\(\lfloor\frac{A+B}C\rfloor=\lfloor\frac AC\rfloor+\lfloor\frac BC\rfloor+\lfloor\frac {(A\ \operatorname{mod}\ C)+(B\ \operatorname{mod}\ C)}C\rfloor\)。

\(\lfloor\frac AC\rfloor\) 和 \(\lfloor\frac BC\rfloor\) 分别只与 \(A,B\) 有关可以各自计算,而 \(\lfloor\frac {(A\ \operatorname{mod}\ C)+(B\ \operatorname{mod}\ C)}C\rfloor\) 在已知 \(A\) 情况下只要求有多少 \(B\ \operatorname{mod}\ C\) 大于等于 \(C-(A\ \operatorname{mod}\ C)\),可以事先拿一个 vector 存下所有 \(B\ \operatorname{mod}\ C\) 并排序,询问时 lower_bound 一下即可。

因此先 dfs 一遍所有可能的较低位,分 \(l\) 存下 \(rk-y\) 并排序。

然后再 dfs 一遍所有可能的最高 \(6\) 位,不足 \(6\) 位直接统计,否则根据预先存下的信息计算。

实现起来可能要注意一些细节,感觉我的写法似乎有点麻烦。

代码:\(O(\sqrt n\log \sqrt n)\)

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Rg register
#define RI Rg int
#define Cn const
#define CI Cn int&
#define I inline
#define W while
#define SZ 1000000
#define V 998244353
#define X 1000000007
#define LL long long
#define Dec(x) (!x--&&(x+=X))
using namespace std;
LL n,nn,p;int ans,tn[7],c[7][7],s[7][7][SZ+1];
void Init(RI x,RI l,CI k)//预处理较低位,存下所有p-x
{
	s[k][l][++c[k][l]]=(++p)-x;if(l==k) return;for(RI i=0;i<=9;++i) Init(x*10+i,l+1,k);
}
void BF(LL x,RI l)//暴力
{
	if(x>n) return;++p;ans=(ans+(p-x)/V-(p<x)+X)%X;for(RI i=0;i<=9;++i) BF(x*10+i,l+1);
}
void Solve(RI x,RI l)//枚举最高6位
{
	if(l^6) {++p,ans=(ans+(p-x)/V-(p<x)+X)%X;for(RI i=0;i<=9;++i) Solve(x*10+i,l+1);return;}//不足6位,直接统计
	if(x==nn) return BF(x,0);//最高6位与n的最高6位相同,直接暴力
	RI i,k;LL v;for(k=0,v=x;k<=6&&v<=n;++k,v*=10);--k;//求出较低位最大长度
	for(i=0;i<=k;++i) v=p-1LL*x*tn[i],ans=(ans+1LL*(v/V-(v<0)+X)*tn[i])%X,//枚举长度,加上的数为p-x*tn[i]
		v=(v%V+V)%V,ans=(ans+tn[i]-(lower_bound(s[k][i]+1,s[k][i]+tn[i]+1,V-v)-s[k][i])+1)%X;//求相加大于等于998244353的数的个数
	for(i=0;i<=k;++i) p+=tn[i];//更新排名
}
int main()
{
	RI i,k,dc;for(scanf("%lld",&n),tn[0]=i=1;i<=6;++i) tn[i]=tn[i-1]*10;
	for(k=0;k<=6;++k) for(p=0,Init(0,0,k),i=0;i<=k;++i) sort(s[k][i]+1,s[k][i]+tn[i]+1);//排序
	if(p=0,n<1e6) for(i=1;i<=9;++i) BF(i,1);else {nn=n;W(nn>=1e6) nn/=10;for(i=1;i<=9;++i) Solve(i,1);}//n小直接暴力,否则nn记录前6位
	return printf("%d\n",(int)(1LL*(X-ans)*V%X)),0;//答案为-ans*998244353
}

标签:lfloor,frac,rfloor,CF1601F,Meet,Sorts,mod,operatorname,define
来源: https://www.cnblogs.com/chenxiaoran666/p/CF1601F.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有