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;
}

 

posted @ 2020-07-22 16:43  kongbursi  阅读(124)  评论(0编辑  收藏  举报