zoukankan      html  css  js  c++  java
  • 清华集训2016 组合数问题

    • 【清华集训2016】组合数问题
    • 其实卢卡斯定理是一个(K)进制拆分的过程。
    • 考虑每一次卢卡斯迭代的过程,实际上就是把最后一位数单独拿出来算,然后把最后一位去掉。
    • 那么如果我们把两个位置上的数都拆分的话,那么就相当于每一个位置上的组合数乘起来。

    [C_{p,q}=prod_{ileq p,jleq q} C_{i,j} ]

    • 所以问题就变成了,有多少个(ileq n,jleq m)的数对((i,j)),满足在(K)进制拆分下的某一位数(i<j)
    • 这个就比较套路了,直接数位(dp)即可,设(f_{i,01,01,01})表示当前在(i)位,是否满足要求,(i)的填法是否危险,(j)的填法是否危险,记忆化即可。
    • 复杂度(O(8*log_kn))
    #include<bits/stdc++.h>
    #define R register int
    #define ll long long 
    using namespace std;
    const int N=100011;
    const int mod=1e9+7;
    const int inv=500000004;
    int t,K,l1,l2,Dc,O1[N],O2[N],C[201][201];
    int f[2][2][2][N];
    ll n,m;
    int gi(){
        R x=0,k=1;char c=getchar();
        while(c!='-'&&(c<'0'||c>'9'))c=getchar();
        if(c=='-')k=-1,c=getchar();
        while(c<='9'&&c>='0')x=(x<<3)+(x<<1)+c-'0',c=getchar();
        return x*k;
    }
    void add(R &x,R y){x=(x+y>=mod?x+y-mod:x+y);}
    int Dfs(R is,R q,R p,R i){
    	if(!i)return is;
    	if(f[is][p][q][i]!=-1)return f[is][p][q][i];
    	R &nw=f[is][p][q][i],lm1=(q?(K-1):O1[i]),lm2=(p?(K-1):O2[i]);
    	nw=0;
    	for(R j=0;j<=lm1;++j)
    		for(R k=0;k<=lm2;++k)
    			add(nw,Dfs(is|(j<k),q|(j<lm1),p|(k<lm2),i-1));
    	return f[is][p][q][i];
    }
    void sol(){
    	scanf("%lld %lld",&n,&m);
    	l1=l2=0,m=min(n,m),Dc=m%mod;
    	memset(f,-1,sizeof(f));
    	while(n)O1[++l1]=(n%K),n/=K;
    	while(m)O2[++l2]=(m%K),m/=K;
    	while(l2<=l1)O2[++l2]=0;
    	R ans=Dfs(0,0,0,l1);
    	add(ans,mod-(1ll*(Dc+1)*Dc%mod*inv%mod));
    	printf("%d
    ",ans);
    }
    int main(){
    	t=gi(),K=gi();
    	while(t--)sol();
    	return 0;
    }
    
    
  • 相关阅读:
    C语言-const和volatile深度分析
    C语言循环语句工程用法
    C分支语句的工程用法
    函数对象分析
    关于protel电路图导入word
    单片机程序编写与下载
    关于Protel输出PDF原理图
    关于定时器、外部中断的一些理解
    锁存、译码介绍
    关于Proteus电压设置
  • 原文地址:https://www.cnblogs.com/Tyher/p/10051430.html
Copyright © 2011-2022 走看看