AT_abc390_g [ABC390G] Permutation Concatenation 题解

这题感觉好难绷。

枚举排列的每一位,然后考虑所有数在这一位时,会对答案总和产生什么贡献。设正在考虑排列的第 \(i\) 个数,十进制位数为 \(j\) 的数有 \(b_j\) 个,总和是 \(sum_j\),我们枚举第 \(i\) 个数十进制下有多少位,那么这一位答案就是:

\[i!(n-i-1)! \times \sum_{i=1}^{6} sum_i \sum_{j=1}^{6}{\binom{b_j-[j=i]}{c_j}10^{j\times c_j}}[\sum c_j = n-i] \]

其中 \(c_j\) 是位数为 \(j\) 的数有多少个放在了后 \(n-i\) 个,也就是垫在当前位的后面。要注意的是式子里面 \(i=j\) 时,因为少一个数,\(b_j\) 要减 \(1\)

这里对 \(c_j\) 的和做出要求,显然是一个背包问题,可以卷积解决。

设:

\[F_j(x) = \sum\limits_{i=0}^{b_j}{10^{ij}\binom{b_j}{i}x^{i}} \]

\[G_j(x) = \sum\limits_{i=0}^{b_j - 1}{10^{ij}\binom{b_j - 1}{i}x^{i}} \]

\[H_j(x) = \dfrac{\prod\limits_{i=1}^{6} F_i(x)}{F_j(x)} \times G_j(x) \]

那么上式就可以变为:

\[i!(n-i-1)! \times \sum_{i=1}^{6} sum_i [x^{n-i}]H_i(x) \]

数据范围不大,直接 NTT 随便乘就行。时间复杂度 \(O(n\log^{3}{n})\),有两个以 \(10\) 为底,跑得还蛮快。

别忘了 \(2\times 10^5\)\(6\) 位。

atcoder library 太牛了。

#include<bits/stdc++.h>
#include<atcoder/all>
inline void rd(){}
template<typename T,typename ...U>
inline void rd(T &x,U &...args){
    int ch=getchar();
    T f=1;x=0;
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    x*=f;rd(args...);
}
#define int long long
const int N=2e5+5,mod=998244353;
int n,fac[N],sum[10],w[N],cnt[N],inv[N];
inline int ch(int x){
	int ans=0;
	while(x)x/=10,++ans;
	return ans;
}
inline int KSM(int x,int n){
	int ans=1;
	while(n){
		if(n&1)ans=1ll*ans*x%mod;
		x=1ll*x*x%mod;
		n>>=1;
	}return ans;
}
inline int C(int n,int m){
	if(n<m)return 0;
	return 1ll*fac[n]*inv[m]%mod*inv[n-m]%mod;
}
std::vector<int> vc[7],b[7],c[7];
signed main(){
    rd(n);
    fac[0]=inv[0]=1;
    for(int i=1;i<=n;i++)fac[i]=fac[i-1]*i%mod;
    for(int i=1;i<=n;i++)inv[i]=KSM(fac[i],mod-2);
    for(int i=1;i<=n;i++)w[i]=ch(i),(sum[w[i]]+=i)%=mod,cnt[w[i]]++;
    for(int i=1;i<=6;i++){
    	int now=1,bas=std::pow(10,i);
    	for(int j=0;j<=cnt[i];j++){
    		b[i].push_back(now*C(cnt[i],j)%mod);
    		c[i].push_back(now*C(cnt[i]-1,j)%mod);
    		now=now*bas%mod;
		}
		c[i].pop_back();
	}
	for(int i=1;i<=6;i++){
		vc[i].push_back(1);
		for(int j=1;j<=6;j++){
			if(j==i)vc[i]=atcoder::convolution<mod>(vc[i],c[j]);
			else vc[i]=atcoder::convolution<mod>(vc[i],b[j]);
		}
	}
	int ans=0;
    for(int i=0;i<n;i++){
    	for(int j=1;j<=6;j++){
    		if((int)vc[j].size()-1<n-i-1)continue;
    		(ans+=vc[j][n-i-1]*sum[j]%mod*fac[n-i-1]%mod*fac[i]%mod)%=mod;
		}
	}
	printf("%lld\n",ans);
    return 0;
}
posted @ 2025-01-26 12:23  KIreteria  阅读(28)  评论(0编辑  收藏  举报