【2020牛客多校第八场 D】Disgusting Relationship 题解

题目大意

  一个置换可以看成是有 a 1 a_1 a1 个长度为 1 1 1 的环 + a 2 a_2 a2 个长度为 2 2 2 的环 + …… + a n a_n an 个长度为 n n n 的环,满足 ∑ i = 1 n i ⋅ a i = n \sum_{i=1}^n i\cdot a_i=n i=1niai=n
  记 f ( a 1 , a 2 , ⋯   , a n ) f(a_1,a_2,\cdots,a_n) f(a1,a2,,an) 表示各种环的数量分别为 a 1 , ⋯   , a n a_1,\cdots,a_n a1,,an、长度为 n n n 的置换的数量,现给定 n , p n,p n,p p p p 是质数),问有多少种不同的数列 a 1 , ⋯   , a n a_1,\cdots,a_n a1,,an,满足 p ∤   f ( a 1 , a 2 , ⋯   , a n ) p \not|\ f(a_1,a_2,\cdots,a_n) p f(a1,a2,,an)

   n ≤ 1 0 18 ,    2 ≤ p ≤ 1 0 5 n \leq 10^{18},~~2 \leq p \leq 10^5 n1018,  2p105
  多测, T ≤ 1 0 5 T \leq 10^5 T105,2s

\\
\\
\\

题解

  明眼人一看就有
f ( a 1 , ⋯   , a n ) = n ! ∏ i = 1 n i a i ⋅ a i ! f(a_1,\cdots,a_n)=\frac{n!}{\prod_{i=1}^n i^{a_i} \cdot a_i!} f(a1,,an)=i=1niaiai!n!

  所以 p p p 不整除这个东西,意思是要让分母的 p p p 因子数量 ≥ \ge 分子的 p p p 因子数量。
  乍一看这个 n n n 这么大,整数拆分、dp 之类的啥都做不了,吓死个人。

  冷静分析.jpg
  首先,这整个分式最终必然得到一个整数(因为这是在计算方案数),这意味着分母的 p p p 因子数量一定是 ≤ \leq 分子的 p p p 因子数量的。而我们的目标又是“分母的 p p p 因子数量 ≥ \ge 分子的 p p p 因子数量”,因此可得:1、我们要让分母、分子的 p p p 因子数量相等;2、这等价于让分母的 p p p 因子数量最大化。

  有了这个目标,就能隐约感觉到, a a a 数列不会长得太奇怪,肯定有限制的。
  接下来就来排除掉一些情况。

  1. 会不会有环长 r > p r>p r>p 却又不是 p p p 的倍数呢?
      注意到这时候 r a r r^{a_r} rar 是没有贡献的,这太浪费了,我们把这 a r a_r ar 个长度为 r r r 的环,每个抽 p p p 出来,组成 a r a_r ar 个长度为 p p p 的环,发现贡献至少多了 a r a_r ar。说明这种情况下分母的 p p p 因子数量没有最大化。
  2. 会不会有环长 r = k p r=kp r=kp k > 1 k>1 k>1)呢?
      同理啊,全部换成环长为 p p p 会使贡献增大:单个 r r r 的贡献从 1 + ( k 的 p 因 子 数 量 ) 1+(k的p因子数量) 1+(kp) 变成 k k k,正常情况下后者都会大于前者;而 a r ! a_r! ar! 部分的贡献从 a r ! a_r! ar! 变成 ( a p + a r ) ! a p ! \frac{(a_p+a_r)!}{a_p!} ap!(ap+ar)!,不会更劣。
      唯一使得单个 r r r 贡献保持不变的是 k = p = 2 k=p=2 k=p=2,但这会在 a r ! a_r! ar! 部分增大贡献。
      所以也不合法。

  所以这就说明 a i a_i ai 非零的只有 i ∈ [ 1 , p ] i \in [1,p] i[1,p] 了。

  我们可以先想像一种初始情况: a 1 = n a_1=n a1=n,这显然是一个合法解。然后看看怎么能把 a 1 a_1 a1 里的东西拿到 a 2 , ⋯   , a p a_2,\cdots,a_p a2,,ap 里去,而保持 p p p 因子数量不变。

  先考虑 n   m o d   p = 0 n \bmod p=0 nmodp=0
  当然可以想到 a 1 a_1 a1 举家迁移到 a p a_p ap,贡献从 ∑ j = 1 ∞ ⌊ n p j ⌋ \sum_{j=1}^\infty \lfloor \frac{n}{p^j} \rfloor j=1pjn 变成 n p + ∑ j = 2 ∞ ⌊ n p j ⌋ \frac np + \sum_{j=2}^\infty \lfloor \frac{n}{p^j} \rfloor pn+j=2pjn,没有变化。如果只是抽 a 1 a_1 a1 的一部分放到 a p a_p ap 里去呢?由于在 p p p 的幂的位置, a 1 ! a_1! a1! p p p 因子数量都会有一次大的提升,所以构成 p p p 的幂的连续段不能拆开考虑,否则 p p p 因子数量一定会减少。比如 a 1 = 14 , p = 2 a_1=14, p=2 a1=14,p=2,那么相当于把 a 1 a_1 a1 分成长度为 8 , 4 , 2 8,4,2 8,4,2 的三个段,每个段要么留在 a 1 a_1 a1 要么搬到 a p a_p ap
  更一般地说,设 n n n p p p 进制表示为 b 1 b 2 ⋯ b m b_1b_2\cdots b_m b1b2bm,那么每个二进制位下的每个单位“1”可以选择留在 a 1 a_1 a1 或搬到 a p a_p ap,因此对答案的贡献为 ∏ i = 1 m − 1 ( b i + 1 ) \prod_{i=1}^{m-1}(b_i+1) i=1m1(bi+1)。(为啥是 m − 1 m-1 m1?最低位一定是 0 0 0,如果不是 0 0 0 的话是下面的情况)

  再考虑 n   m o d   p > 0 n \bmod p>0 nmodp>0
  显然这个多出来的部分放哪都无所谓,都不会产生任何 p p p 因子,因此这里对答案的贡献是 n m o d    p n \mod p nmodp 的可重整数拆分。

  综上,答案为
a n s = p a r t ( n   m o d   p ) ⋅ ∏ i = 1 m − 1 ( b i + 1 ) ans=part(n \bmod p) \cdot \prod_{i=1}^{m-1}(b_i+1) ans=part(nmodp)i=1m1(bi+1)

  其中 b 1 b 2 ⋯ b m b_1b_2\cdots b_m b1b2bm n n n p p p 进制表示, p a r t part part 表示可重整数拆分方案数。后者五边形数 O ( n n ) O(n \sqrt n) O(nn ) 或者 O ( n log ⁡ n ) O(n \log n) O(nlogn) 预处理一下就完事了。

代码

#include<bits/stdc++.h>
#define fo(i,a,b) for(int i=a;i<=b;i++)
using namespace std;

typedef long long LL;

const int maxp=1e5+5;
const LL mo=1e9+7;

LL n;
int p;

int w[maxp],w0;
LL f[maxp];
void Pre_part(int n)
{
	for(int i=1; w[w0]<n; i++)
	{
		w[++w0]=i*(3*i-1)>>1;
		w[++w0]=i*(3*i+1)>>1;
	}
	f[0]=1;
	fo(i,1,n)
		for(int j=1; w[j]<=i; j++) (f[i]+=((((j-1)>>1)&1) ?-1 :1)*f[i-w[j]])%=mo;
}

int T;
int main()
{
	Pre_part(1e5);
	
	scanf("%d",&T);
	fo(ti,1,T)
	{
		scanf("%lld %d",&n,&p);
		
		LL ans=f[n%p];
		for(n/=p; n; n/=p) (ans*=n%p+1)%=mo;
		
		printf("Case #%d: %lld\n",ti,(ans+mo)%mo);
	}
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值