zoukankan      html  css  js  c++  java
  • 【BZOJ4870】[Shoi2017]组合数问题 动态规划(矩阵乘法)

    【BZOJ4870】[Shoi2017]组合数问题

    Description

    Input

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

    Output

    一行一个整数代表答案。

    Sample Input

    2 10007 2 0

    Sample Output

    8

    题解:题意:nk个数,选出一些数,使得选出来的数的个数%k=r的方案数(所以就不要管原来的题面了!)

    然后这变成了一道动态规划题,由于nk很大我们试着用矩阵乘法,发现很容易就能构造出转移矩阵,具体不说了

    当然,如果不强行使用矩乘的话也是可以搞的,设f[i][j]表示i个数,取出一些数使得个数%k=j的方案数,然后可以得到转移方程

    f[i*2][(j+j')%k]+=f[i][j]*f[i][j']

    显然这个式子是满足可加性的,所以可以直接用倍增的思想搞一搞,时间复杂度比矩乘还少一个n

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    using namespace std;
    typedef long long ll;
    ll n,p;
    ll k,r;
    typedef struct matrix
    {
    	ll v[60];
    }M;
    M x,ans,emp;
    M mpls(M a,M b)
    {
    	M c=emp;
    	int i,j;
    	for(i=0;i<k;i++)
    		for(j=0;j<k;j++)
    			c.v[(i+j)%k]=(c.v[(i+j)%k]+a.v[i]*b.v[j])%p;
    	return c;
    }
    void pm(ll y)
    {
    	while(y)
    	{
    		if(y&1)	ans=mpls(ans,x);
    		x=mpls(x,x),y>>=1;
    	}
    }
    int main()
    {
    	scanf("%lld%lld%d%d",&n,&p,&k,&r);
    	ans.v[0]=1,x.v[0]=1,x.v[1%k]++;
    	pm(n*k);
    	printf("%lld",ans.v[r]);
    	return 0;
    }
  • 相关阅读:
    随笔 祝我快乐
    .NET设计模式单件模式(Singleton Pattern)
    随笔 缘分
    随笔 雨季
    数据库设计中的小经验
    一个字节造成的巨大性能差异——SQL Server存储结构
    随笔 淡淡的幸福
    用LINQ还是NHibernate?
    随笔 风筝
    FreeStyle Wishes
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/6855158.html
Copyright © 2011-2022 走看看