zoukankan      html  css  js  c++  java
  • 六省联考:组合数问题

    4870: [Shoi2017]组合数问题

    2017-09-03


    Description


    Input

    第一行有四个整数 n, p, k, r,所有整数含义见问题描述。
    1 ≤ n ≤ 10^9, 0 ≤ r < k ≤ 50, 2 ≤ p ≤ 2^30 − 1

    Output

    一行一个整数代表答案。

    INPUT_1

    2 10007 2 0

    INPUT_2

    20 10007 20 0


    OUT_1

    8

    OUT_2

    176


    并不知道这个是什么玄学(组合数),但是这个题并不是裸组合数,因为联考时用组合数递推只得了30poi....
    然后因为k比较小,n比较大,Lucas定理就不能用了,乘法逆元只能解决n<=10^5的T;显然这个题不能用
    只能回归组合数定义f[i][j]=f[i-1][j]+f[i-1][(j-1+k)%k]
    用矩阵加速这个过程。
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstdlib>
    #include<cstring>
    #define ll long long 
    using namespace std;
    ll read(){
        ll an=0,f=1;char ch=getchar();
        while(!('0'<=ch&&ch<='9')){if(ch=='-')f=-f;ch=getchar();}
        while('0'<=ch&&ch<='9'){an=an*10+(ch-'0');ch=getchar();}
        return an*f;
    }
    struct saber{
    ll a[60][60];
    }ans,d;
    ll n,p;
    int k,r;
    saber operator *(saber A,saber B){
        saber c;
        for(int i=0;i<=50;i++)
        for(int j=0;j<=50;j++)c.a[i][j]=0;
        
        for(int i=0;i<k;i++)
            for(int  j=0;j<k;j++)
                for(int  l=0;l<k;l++)
                    c.a[i][j]=(c.a[i][j]+A.a[i][l]*B.a[l][j])%p;
        if(k==1)c.a[0][0]=((ll)A.a[0][0]*B.a[0][0]+c.a[0][0])%p;
        return c;
    }
    saber kp(ll kk){
        saber f;
        for(int i=0;i<=50;i++)
        for(int j=0;j<=50;j++)f.a[i][j]=0;
        for(ll i=0;i<k;i++)f.a[i][i]=1;
        while(kk){
            if(kk&1)f=f*d;
            d=d*d;
            kk>>=1;
        }
        return f;
    }
    int main(){
        n=read();p=read();k=read();r=read();
        for(int i=0;i<k;i++){
            d.a[i][i]=1;
            d.a[i][(i-1+k)%k]=1;
        }
        ans=kp(n*k);
        cout<<ans.a[r][0];
        return 0;
    }
    s_a_b_e_r

    by:s_a_b_e_r


     表示当时省选划水的时候还是一只只会模拟的萌新qwq
    这个题乍一看就是一数学题,然而推半天公式只能得到完全不可做的结论qwq
    事实上这题跟组合数学基本没啥关系
    组合数一开始的定义就是在n个数中取m个数的方案数
    此处可有递推方程(f[i][j]=f[i-1][j]+f[i-1][j-1])
    这题稍微变了一下条件
    在i个数中取x个数使得x%k==j
    于是有递推方程f[i][j]=f[i-1][j]+f[i-1][(j-1+k)%k]
    然而数据范围O(n*k)==TLE。
    需要加一个优化
    因为楼上说的优化我都不会,于是去学矩阵加速
    按照递推方程构造出矩阵
    然后就可以矩阵快速幂解决了
    是不是很快x
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define ll long long
    using namespace std;
    ll n,p,k,r;
    struct matrix{
    ll a[55][55];
    }ans,m;
    matrix operator * (matrix x,matrix y)
    {
         matrix s;
         memset(s.a,0,sizeof(s.a));
         for(int i=0;i<k;++i)
         for(int j=0;j<k;++j)
         for(int l=0;l<k;++l)
         s.a[i][j]=(s.a[i][j]+x.a[i][l]*y.a[l][j])%p;
         if (k==1) s.a[0][0]=(s.a[0][0]+x.a[0][0]*y.a[0][0])%p;
         return s;
    }
    matrix kp(ll q)
    {
           matrix s;
           memset(s.a,0,sizeof(s.a));
           for(int i=0;i<k;++i)s.a[i][i]=1;
           while(q)
           {
             if(q&1)s=s*m;
             m=m*m;
             q>>=1;
           }
           return s;
    }
    int main()
    {
        cin>>n>>p>>k>>r;
        for(int i=0;i<k;++i)
        {
          m.a[i][i]=1;
          m.a[i][(i-1+k)%k]=1;
        }
        matrix ans=kp(n*k);
        printf("%lld",ans.a[0][r]);
        return 0;
    }
    4870(wypx)
    by:wypx
    s:评测机又卡了
    w:我连自动售货机都能卡x
     
     
  • 相关阅读:
    postgres导入和导出
    postgres日常操作
    NumPy Ndarray 对象
    NumPy 简介及安装
    Python两个内置函数locals 和globals
    python之multiprocessing多进程
    postgres外部表
    css中文本超出部分省略号代替
    js中的作用域链
    css中clip:rect矩形剪裁功能
  • 原文地址:https://www.cnblogs.com/ck666/p/7471117.html
Copyright © 2011-2022 走看看