【Educational Codeforces Round 88 (Rated for Div. 2) E】Modular Stability

题目链接

请不要点我!

题目大意

你给一个整数n一个整数k

让你找这么一个数组a[1],a[2],...,a[k]

其中1<=a[1]<a[2]<....<a[k]<=n

使得对于任意一个非负整数x,让它按照 任意顺序 依次去和这个数组的每个元素取模(x和第1个元素取模后,结果再和第2个元素取模...)。

得到的取模的结果都要相同。

请你求出符合要求的数组a的个数。

题解

最后选的序列,一定是每个数字都是最小的那个数字a[1]的倍数。

为啥?

假设,存在某个数字a[i],这个a[i]不是a[1]的倍数。

那么我们看两个取模的顺序[a[1],a[2],...a[k]]和[a[i],a[1],a[2],...a[i-1],a[i+1],...a[k]]

我们取 x=a[i] ,先让x对第一个顺序的进行取模。

会发现,因为x%a[1]!=0,所以x对a[1]取余之后,设新的x为ans1,则0<ans1<a[1]<a[2]...a[k]

这意味着什么呢? 实际上这就表明,ans1再和后面的a[2..k]进行取模,结果还是ans1。(因为和一个比自己大的数字取模,还是本身嘛)

那x和第二个顺序的进行取模会怎么样呢?发现x=a[i]和a[i]先取模,变成0了!再取模也没用,肯定 都是0

所以,只要数组中有不是a[1]的倍数的,那么把它放在最开头和x=a[i]进行取模,那个取模的顺序结果 ans2肯定等于0

而ans1经过上面的分析,随便取x=某个不是a[1]倍数的数字,和a[1]进行取模操作结果为ans1,ans1都会小于a[2],a[3]..a[k]从而最后 取余结果就是ans1(不等于0)

所以,取的k-1个数字肯定都是a[1]的倍数。

然后再正面说下为啥都是a[1]的倍数就行,因为你和k*a、a取模的话(不管什么样的顺序),最后的结果肯定是和a直接取模相同的(这个不想证啦。。感觉很显然对吧。。)。

而a[1]的倍数有n/a[1]个,去掉a[1]还有 \(n/a[1] - 1\) 个, 从中选出k-1个, 则累加的序列个数就为 \(C^{k-1}_{n/a[1]-1}\) 个。

枚举a[1]等于1..n-k+1然后累加组合数就好。

组合数要用到乘法逆元,预处理一下n!和1/n!对MOD取余的结果就好。

总结

这题关键点在于猜到最后结论,一定每个数都是a[1]的倍数这点, 猜到这一点, 然后试试发现。

不管怎么样取模,最后都和直接与a[1]取模的结果相同。问题就解决啦。

题解

#include<bits/stdc++.h>
#define ll long long
#define rei(x) scanf("%d",&x)
#define rel(x) scanf("%I64d",&x)
#define rep1(i,a,b) for (int i = a;i <= b;i++)
#define rep2(i,a,b) for (int i = a;i >= b;i--)
using namespace std;

const ll MOD = 998244353;

const int N = 5e5;

int n,k;
ll fac[N+10],rfac[N+10];

/*
    n!/((n-m)!*m!)
*/
ll combinations(int n,int m){
    return fac[n]*rfac[n-m]%MOD*rfac[m]%MOD;
}

ll _pow(ll x,ll y){
    ll ans = 1;
    while (y>0){
        if (y&1){
            ans = ans * x%MOD;
        }
        x = (x*x)%MOD;
        y = y/2;
    }
    return ans;
}

int main(){
    #ifdef LOCAL_DEFINE
        freopen("D:\\rush.txt","r",stdin);
    #endif
    ios::sync_with_stdio(0),cin.tie(0);
    fac[0] = 1;fac[1] = 1;
    rep1(i,1,N) fac[i] = fac[i-1]*i%MOD;
    rfac[N] = _pow(fac[N],MOD-2);
    rep2(i,N-1,0) rfac[i] = rfac[i+1]*(i+1)%MOD;
    cin >> n >> k;
    ll ans = 0;
    rep1(i,1,n){
        int tmp = n/i;
        tmp--;
        if (tmp<k-1) break;
        ans = ans + combinations(tmp,k-1);
        ans%=MOD;
    }
    cout<<ans<<endl;
    return 0;
}

posted @ 2020-06-06 21:09  AWCXV  阅读(123)  评论(0编辑  收藏  举报