zoukankan      html  css  js  c++  java
  • 【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;
    }
    
    
  • 相关阅读:
    windows mobile licence
    通过acme.sh生成泛域名证书
    枚举值为何为1、2、4、8、16....
    script 解决 跨域访问
    强大的json字符串对象,转化为object对象
    使用maven jetty调试web程序
    web上实现起点到终点的抛物线轨迹运动——补充
    实现2个有序数组的排序
    maven axis2简单部署webservice
    使用javamail发送邮件
  • 原文地址:https://www.cnblogs.com/AWCXV/p/13056442.html
Copyright © 2011-2022 走看看