zoukankan      html  css  js  c++  java
  • bzoj 4870: [Shoi2017]组合数问题 [矩阵乘法优化dp]

    4870: [Shoi2017]组合数问题

    题意:求

    [sum_{i=0}^{n-1} inom{nk}{ik+r} mod p ]

    (n le 10^9, 0le r < k le 50)


    组合数推了一下,有一些有趣的性质但是并不好做

    想到了从意义方面考虑,但是没有深入,去看了题解


    n大k小,一副矩乘的样子

    就是求“n个物品取模k余r个的方案数”

    因为取的个数模k,变得很有意思,可以把组合数的递推式矩乘了...

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    typedef long long ll;
    inline int read() {
    	char c=getchar(); int x=0,f=1;
    	while(c<'0' || c>'9') {if(c=='-')f=-1; c=getchar();}
    	while(c>='0' && c<='9') {x=x*10+c-'0'; c=getchar();}
    	return x*f;
    }
    
    int n, mo, k, r;
    struct matrix {
    	int a[51][51];
    	matrix() {memset(a, 0, sizeof(a));}
    	int* operator [](int x) {return a[x];}
    } f, a;
    matrix operator *(matrix a, matrix b) {
    	int n = k;
    	matrix c;
    	for(int i=0; i<n; i++)
    		for(int k=0; k<n; k++) if(a[i][k])
    			for(int j=0; j<n; j++) if(b[k][j])
    				c[i][j] = (c[i][j] + (ll) a[i][k] * b[k][j] %mo) %mo;
    	return c;
    }
    matrix operator ^(matrix a, ll b) {
    	int n = k;
    	matrix c; 
    	for(int i=0; i<n; i++) c[i][i] = 1;
    	for(; b; b>>=1, a=a*a) if(b&1) c=c*a;
    	return c;
    }
    
    int Pow(ll a, int b) {
    	ll ans=1;
    	for(; b; b>>=1, a=a*a%mo)
    		if(b&1) ans=ans*a%mo;
    	return ans;
    }
    int main() {
    	freopen("in", "r", stdin);
    	n=read(); mo=read(); k=read(); r=read();
    	if(k == 1) {printf("%d", Pow(2, n)); return 0;}
    	for(int i=0; i<k; i++) f[i][i] = 1, f[(i+1)%k][i] = 1;
    	f = f ^ ((ll) n * k);
    	a[0][0] = 1;
    	a = f * a;
    	printf("%d
    ", a[r][0]);
    }
    
    
  • 相关阅读:
    其他
    Win10
    Win10
    面向对象与设计模式
    Git
    Java
    Git
    Git
    Git
    一、I/O操作(File文件对象)
  • 原文地址:https://www.cnblogs.com/candy99/p/6771213.html
Copyright © 2011-2022 走看看