zoukankan      html  css  js  c++  java
  • 「清华集训2016」组合数问题(数位dp)

    「清华集训2016」组合数问题(数位dp)

    题意:

    给定\(n,m,k\) 求:\(\sum_1^n\sum_1^{min(i,m)} [k|C(i,j)]\)

    分析:

    根据\(\text{lucas}\)定理,\(C(i,j)=C(i\mod k,j\mod k)C(\frac{i}{k},\frac{j}{k})\)

    只要出现一个\(i \mod k>j \mod k\)\(\frac{i}{k},\frac{j}{k}\)就会出现

    模拟一下这个递归过程,就会发现每次出现的\(i \mod k ,j \mod k\)就是把\(k\)进制下的\(i,j\)依次拆开

    所以只要\(k\)进制下\(j\)有一位大于\(i\)即可,数位dp

    
    const int P=1e9+7;
    
    int t,k;
    ll A,B;
    int a[70],b[70];
    
    ll dp[62][2][2][2][2];
    
    ll dfs(int p,int lim1,int lim2,int lim3,int fl) { 
                 // i是否受到限制,j是否受到限制,是否出现了i>j的位置,是否出现了i<j的位置
    	if(p==0) return fl;
    	if(~dp[p][lim1][lim2][lim3][fl]) return dp[p][lim1][lim2][lim3][fl];
    	ll ans=0;
    	rep(i,0,lim1?a[p]:k-1) rep(j,0,lim2?b[p]:k-1) {
    		if(!lim3 && i<j) continue;
    		ans=(ans+dfs(p-1,lim1&&(i==iend),lim2&&(j==jend),lim3||(i>j),fl||(i<j)))%P;
    	}
    	return dp[p][lim1][lim2][lim3][fl]=ans;
    }
    
    
    ll Solve() {
    	int c1=0,c2=0;
    	memset(a,0,sizeof a),memset(b,0,sizeof b);
    	while(A) a[++c1]=A%k,A/=k;
    	while(B) b[++c2]=B%k,B/=k;
    	return dfs(max(c1,c2),1,1,0,0);
    }
    
    int main(){
    	t=rd(),k=rd();
    	rep(kase,1,t) {
    		A=rd<ll>(),B=rd<ll>();
    		memset(dp,-1,sizeof dp);
    		printf("%lld\n",Solve());
    	}
    }
    
    
    
  • 相关阅读:
    使用MyBatis生成插件
    关联源码及日志
    下载依赖
    框架简介及基本使用
    注解的本质 及 反射读取属性值
    元注解
    广告系统学习笔记(一)
    Nginx学习笔记(三)
    Nginx学习笔记(二)
    Nginx学习笔记(一)
  • 原文地址:https://www.cnblogs.com/chasedeath/p/12721783.html
Copyright © 2011-2022 走看看