Educational Codeforces Round 88 (Rated for Div. 2) E、Modular Stability 逆元+思维
题目链接:E、Modular Stability
题意:
给你一个n数,一个k,在1,2,3...n里挑选k个数,使得对于任意非负整数x,对于这k个数的任何排列顺序,然后用x对这个排列一次取模,如果最后取模结果不变,那么称它为稳定的,求稳定数组的个数。
题解:
我们知道y%x%y!=y%y%x,那么如果要想满足题意那么这个最后的结果应该是0,也就是说这n个数里面那一个最小的x,这个x可以把剩下k-1个数整除,这样的话结果就肯定是0
比如如果k=3,n=10,那么(2,4,6,8,10),我们只需要从中拿出来3个就可以,也就是排列组合C35 ,这里我们只举例x==2
因为要用到排列组合,所以这里用到了逆元的费马小定理推导,具体见:https://www.cnblogs.com/kongbursi-2292702937/p/10582258.html
代码:
#include<stdio.h> #include<algorithm> #include<iostream> #include<string> #include<queue> #include<deque> #include<string.h> #include<map> #include <iostream> #include <math.h> #define Mem(a,b) memset(a,b,sizeof(a)) const double II = acos(-1); const double PP = (II*1.0)/(180.00); using namespace std; typedef long long ll; const int INF=0x3f3f3f3f; const int maxn=5e5+10; const double eps=1e-6; const double PI=acos(-1); const int mod=998244353; ll v[maxn],n,k; void find_divide() { for(ll i=1;i*k<=n;++i) { v[i]=n/i-1; } } ll ppow(ll a,ll b) { ll ans=1; while(b) { if(b&1) ans=(ans*a)%mod; a=(a*a)%mod; b>>=1; } return ans; } ll solve(ll now,int num) { ll ans=1; for(ll i=v[now];i>v[now]-num;--i) ans=(ans*i)%mod; for(ll i=1;i<=num;++i) { ans=(ans*ppow(i,mod-2))%mod; } return ans; } int main() { ll sum=0; scanf("%I64d%I64d",&n,&k); find_divide(); for(ll i=1;i*k<=n;++i) { sum=(sum+solve(i,k-1))%mod; //printf("%d**\n",sum); } printf("%I64d\n",sum); return 0; }