描述
2044年,Picks建成了人类第一台基于量子理论的银河系信息传递机。
Picks游遍了宇宙,雇用了 个外星人来帮他作为信息传递机的中转站。我们将外星人依次编号为
到
,其中
号外星人有
根手指。
外星人都是很低级的,于是Picks花费了很大的精力,才教会他们学会扳手指数数。
Picks现在准备传递 个脉冲信号给VFleaKing,于是他把信号发给
号外星人,然后
号外星人把信号发送给
号外星人,
号外星人把信号发送给
号外星人,依次类推,最后
号外星人把信号发给VFleaKing。
但是事情没有Picks想象的那么顺利,由于外星人手指个数有限,所以如果 号外星人收到了
个脉冲信号,他会错误的以为发送过来的是
个脉冲信号,导致只发送了
个脉冲信号出去。
Picks希望他发送出去的脉冲信号数量 与VFleaKing收到的脉冲信号数量
的差的绝对值尽量小。于是他决定通过重新排列这些外星人的顺序来达到这一目的。请你求出与
之差最小的
。除此之外,请求出有多少种排列外星人的方式能达到最优解,你只需要输出方案数对
(
,一个质数)取模后的结果。
输入格式
第一行两个正整数 。
接下来一行有 个正整数
,表示
号外星人的手指数。
输出格式
第一行一个整数表示最优情况下VFleaKing收到的脉冲数量。
第二行一个整数表示达到最优情况的方案数。
这些外星人原来并不是一个种族的=_=
题解(参考官方题解)
首先考虑
解决第一个问
枚举当前的脉冲信号个数,然后枚举一遍所有外星人,得出传递到下一步的脉冲信号个数
若最小的 为
,那么最后的结果一定
,只需要找到可行的最大的小于
的个数即可
虽然题目有限制,每一个外星人只能使用 次,而我们的枚举会把每个外星人枚举
次,看似会重复使用,但是实际上每个外形人也只能使用
次。使用
过后的结果一定小于
,因此再多使用一次也不会改变结果。
考虑较高复杂度解决第二个问
我们对于当前的 ,相同的
仍然对应不同的情况,因为对于
,使用后是不会影响
的结果的。所以说我们对于每一个
,需要记录当前还有多少个
,如此一来我们就能够得到一个使用
递推
![F[x][i]+=F[x][i+1]](https://i-blog.csdnimg.cn/blog_migrate/1d698f808b7213554476cd591af45fdf.png)
而对于另外的 ,则有
![F[x \mod a_i][i+C[x]-C[a_i]]+=F[x][i]](https://i-blog.csdnimg.cn/blog_migrate/d4a876ca084b931064b408a7f35a5ef3.png)
此处 表示
的
的个数
而 对应的则是增加的
的个数
大概算一下吧
①枚举
②枚举
③枚举
共三层,复杂度约为
尝试简化
上面的两维状态尝试先减去第一维,也就是说记录当前某一类数字的个数,我发现我做不到
于是就按照官方题解把第二维省去
表示当前剩余的脉冲信号个数
那么我们就要想如何快速进行剩余的 数字个数的讨论
由于省去了第二维,所以我们在当前讨论 的时候就把
的数字讨论掉,这样子才不会出现多余的那一维
对于 ,剩余的位子实际上为
个,而下一个位子必定由
占领,而由
占领之后,其余的
则可以任意占领后面的位子,只有
的数字必须保持一定的顺序,或者说它们的顺序由后面的的讨论决定,我们当前无法确定这些数字的位置
因此这 的排列方案数为
递推式满足
![f[x \mod a_i]+=f[x]\cdot\frac{(C[x]-1)!}{C[a_i]!}](https://i-blog.csdnimg.cn/blog_migrate/c1dbf365b7b0bce68ab44f78e2b40377.png)
时间复杂度减少为 ,空间复杂度减少为
附上代码
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const long long mod=998244353;
bool mark[5678];
long long inv[5678],fac[5678],f[5678];
int n,x,mn=1e9,mx=0,C[5678],A[1234];
int main()
{
scanf("%d%d",&n,&x);
inv[1]=inv[0]=fac[0]=1;
for(int i=2;i<=x;i++)inv[i]=-(mod/i)*inv[mod%i]%mod;
for(int i=2;i<=x;i++)inv[i]=(inv[i]*inv[i-1]%mod+mod)%mod;
for(int i=1;i<=n;i++)
{
scanf("%d",&A[i]);
C[A[i]]++;
mn=min(mn,A[i]);
mx=max(mx,A[i]);
}
for(int i=1,mix=max(mx,x);i<=mix;i++)C[i]+=C[i-1];
for(int i=1,mix=max(mx,n);i<=mix;i++)fac[i]=fac[i-1]*i%mod;
sort(A+1,A+n+1);
f[x]=fac[C[mx]]*inv[C[x]]%mod;
mark[x]=1;int t=x;
for(x=x;x;x--)
if(mark[x])
{
for(int k=1;k<=n&&A[k]<=x;k++)
{
mark[x%A[k]]=1;
f[x%A[k]]=(f[x%A[k]]+f[x]*fac[C[x]-1]%mod*inv[C[x%A[k]]])%mod;
}
}
for(int i=mn-1;i>=0;i--)
if(mark[i])
{
printf("%d\n%lld",i,f[i]<0?f[i]+mod:f[i]);
return 0;
}
}
复制代码