[海军国际项目办公室]CSP 2020

Posted StaroForgin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[海军国际项目办公室]CSP 2020相关的知识,希望对你有一定的参考价值。

CSP 2020

题目概述


题解

为什么会有人取这么奇怪的题目名。

首先,我们可以通过 打表 简单推理发现一个性质,在较大的 n n n下,我们真正答案的长度与 n 3 n^3 n3所能构成的最短的字符串的长度相近。
事实上也很好证明,因为我们是将 n 3 n^3 n3分解得到第 n 4 n^4 n4小的数,最短的字符串可能由于刚好挤满,所以不能排到 n 4 n^4 n4,但如果刚好比最短的字符串长度大一,就完完全全可以排到第 n 4 n^4 n4小的数了。
所以我们可以先判断一下我们答案的字符串长度,只可能是 ⌈ n 3 9 ⌉ \\lceil\\frac{n^3}{9}\\rceil 9n3或者 ⌈ n 3 9 ⌉ + 1 \\lceil\\frac{n^3}{9}\\rceil+1 9n3+1
而由于我们的长度与最短长度非常接近,所以事实上我们的该字符串中绝大部分位置都是 9 9 9
我们记我们的答案字符串为 a a a,事实上 ∑ ( 9 − a ) ⩽ 14 \\sum (9-a)\\leqslant 14 (9a)14,也就是说我们从一个全是 9 9 9的串中,减去不超过 13 13 13 1 0 x 10^x 10x就可以得到我们的答案。

我们可以用二分的方法,找到我们那即为需要减,将其减去。
但如果要二分的话,我们相当于要知道比我们在 x x x这位减一个 1 1 1要小的方法的数量。
显然,如果要比这样减小,那肯定是在 x x x这位前面减了一个 1 1 1,方法数很容易求出。
我们记 g ( x , y ) g(x,y) g(x,y)表示在一个长度为 y y y的全是 9 9 9的串中,选出 y y y 1 1 1减的方法数。
前面的方案可以有 g g g差分得出,我们只需要从随便选中减去一个大于 x x x都不选的方法即可,也就是 g ( n , y ) − g ( x , y ) g(n,y)-g(x,y) g(n,y)g(x,y)

但我们的 g g g函数又可以怎么求呢?
其实这东西的求法应该很容易联想到我们的斯特林反演,但是我们在每一位上都不能选择超过 9 9 9个,所以还得改改,我们记 d p i , j dp_{i,j} dpi,j就是在一个长度为 i i i的全是 9 9 9的串中,每一位至少被选择一个,总共选择 j j j个的方法数。
容易得到 d p dp dp转移式, d p i , j = ∑ k = 1 min ⁡ ( 9 , j ) d p i − 1 , j − k dp_{i,j}=\\sum_{k=1}^{\\min(9,j)dp_{i-1,j-k}} dpi,j=k=1min(9,j)dpi1,jk
显然,我们可以知道,
g ( x , y ) = ∑ i = 0 min ⁡ ( x , y ) ( x i ) d p i , y g(x,y)=\\sum_{i=0}^{\\min(x,y)}\\binom{x}{i}dp_{i,y} g(x,y)=i=0min(x,y)(ix)dpi,y接下来,我们只需要在原数中找到那些为我们要减去,枚举它们要减去多少位就可以了。
实际上真正需要减去的位上的数量也是比较少的。
我们对于 [ 5 , n ] [5,n] [5,n]中每个数都这样跑一次就行了,较小的 [ 1 , 4 ] [1,4] [1,4]部分可以打表。

时间复杂度 O ( n l o g   n ) O\\left(nlog\\,n\\right) O(nlogn),但常数可能不太小。
不过跑得还是很快,只要 111 m s 111ms 111ms

源码

#include<bits/stdc++.h>
using namespace std;
#define MAXN 1005
#define lowbit(x) (x&-x)
#define reg register
#define pb push_back
#define mkpr make_pair
#define fir first
#define sec second
typedef long long LL;
typedef unsigned long long uLL;       
const int INF=0x3f3f3f3f;       
const int mo=998244353;
const int inv2=499122177;
const double jzm=0.997;
const int zero=10000;
const int orG=3,invG=332748118;
const LL lim=1e18+1LL;
const double Pi=acos(-1.0);
const double eps=1e-5;
typedef pair<LL,int> pii;
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){
	_T f=1;x=0;char s=getchar();
	while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
	while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
	x*=f;
}
template<typename _T>
void print(_T x){if(x<0){x=(~x)+1;putchar('-');}if(x>9)print(x/10);putchar(x%10+'0');}
int gcd(int a,int b){return !b?a:gcd(b,a%b);}
int add(int x,int y,int p){return x+y<p?x+y:x+y-p;}
void Add(int &x,int y,int p){x=add(x,y,p);}
int qkpow(int a,LL s,int p){int t=1;while(s){if(s&1LL)t=1ll*a*t%p;a=1ll*a*a%p;s>>=1LL;}return t;}
LL n,p,dp[20][20],pw9[40];
LL mul(LL x,LL y){return (x&&lim/x<y)?lim:min(x*y,lim);}
LL C(int x,int y){
	LL res=1;
	for(int i=x;i>x-y&&res!=lim;i--)res=mul(res,1ll*i);
	if(res==lim)return res;
	for(int i=1;i<=y;i++)res/=1ll*i;
	return res;
}
LL work(int x,int y){
	LL res=0,sum=1;
	for(int i=0;i<=min(x,y)&&res!=lim;i++){
		res=min(res+mul(sum,dp[y][i]),lim);
		sum=mul(sum,x-i);sum/=1ll*(i+1);
	}
	return res;
}
LL sakura(int len,int num,LL sum,int up){
	if(!num)return 0;
	for(int i=min(up,num);i>0;i--){
		LL tmp=work(len-1,num-i);
		if(sum<=tmp)return add(1ll*i*qkpow(10,len-1,p)%p,sakura(len-1,num-i,sum,9),p);
		sum-=tmp;
	}
	LL all=work(len-1,num);int l=1,r=len-1;
	while(l<r){
		int mid=l+r>>1;LL tmp=all-work(mid,num);
		if(tmp<sum)r=mid;else l=mid+1;
	}
	LL tmp=all-work(l,num);
	return add(qkpow(10,l-1,p),sakura(l,num-1,sum-tmp,8),p);
}
signed main(){
	freopen("number.in","r",stdin);
	freopen("number.out","w",stdout);
	read(n[海军国际项目办公室]打拳

[海军国际项目办公室]羽未

[海军国际项目办公室]石子游戏

[海军国际项目办公室]游戏

[海军国际项目办公室]假人

[海军国际项目办公室]快递