CSP模拟赛20191111 密码(数位DP)

在这里插入图片描述
n < = 1 e 1000 , p < = 1 e 9 , k < = 1 e 9 n<=1e1000,p<=1e9,k<=1e9 n<=1e1000,p<=1e9,k<=1e9
请注意 p   i s   p r i m e p \ is \ prime p is prime

对于一个 ( l s ) = l ! s ! ( l − s ) ! \binom ls = \frac {l!}{s!(l-s)!} (sl)=s!(ls)!l!
其含有的 p p p的最大次数 k k k满足 p k ∣ ( l s ) p^k | \binom ls pk(sl)为:
k = ∑ i l p i − s p i − l − s p i k = \sum_{i} \frac l{p^i} - \frac s{p^i} - \frac {l-s}{p^i} k=ipilpispils
我们在 p p p进制下看待这个问题。
k k k就是在 p p p进制下 s s s l − s l-s ls做加法时进了多少位。
所以转进制后直接数位 D P DP DP即可。
一开始没想到数位 D P DP DP可以直接维护进位什么的。。。。。。。
标程写得好。

A C   C o d e \rm AC \ Code AC Code

#include<bits/stdc++.h>
#define maxn 4005
#define mod 1000000007
#define LL long long
using namespace std;

char S[maxn];
int p,K,la,lb,f[2][maxn][2][2];
LL a[maxn],b[maxn];

int cal(int x){ return 1ll * x * (x+1) / 2 % mod; }

int main(){
	
	freopen("password.in","r",stdin);
	freopen("password.out","w",stdout);
	
	scanf("%s%d%d",S,&p,&K),la=strlen(S);
	for(int i=0;i<la;i++) a[i]=S[la-i-1]-'0';
	for(;la;){
		for(int i=la-1;i>=0;i--){
			if(i) a[i-1] += a[i] % p * 10;
			else b[lb++] = a[i] % p;
			a[i] /= p;
		}
		for(;la && !a[la-1];la--);
	}
	if(K > lb){
		puts("0");
		return 0;
	}
	int nw = 1 , pe = 0;
	f[nw][0][0][1] = 1;
	for(int i=lb-1;i>=0;i--){
		swap(nw,pe);
		memset(f[nw],0,sizeof f[nw]);
		for(int j=0;j<lb-i;j++)
			for(int k=0;k<2;k++){
				int pf = f[pe][j][k][1] , pb = f[pe][j][k][0];
				for(int e=0;e<2;e++){
					int nj = (j == K ? j : j+e);
					int &nf = f[nw][nj][e][1] , &nb = f[nw][nj][e][0];
					if(!k){
						nb = (nb + (LL)pb*cal(p-e) + (LL)pf*cal(b[i]-e) ) % mod;
						nf = (nf + (LL)pf*(b[i]-e+1)) % mod;
					}				
					else{
						nb = (nb + (LL)pb*cal(p+e-1) + (LL)pf*(cal(p+e-1)-cal(p+e-1-b[i]))) % mod;
						nf = (nf + (LL)pf*(p+e-1-b[i])) % mod;
					}
				}
			}
	}
	printf("%d\n",((f[nw][K][0][0]+f[nw][K][0][1])%mod+mod)%mod);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值