bzoj 1902: Zju2116 Christopher lucas定理 && 数位DP
1902: Zju2116 Christopher
Time Limit: 1 Sec Memory Limit: 64 MBSubmit: 172 Solved: 67
[Submit][Status][Discuss]
Description
给定n个元素,要从中间选择m个元素有多少种方案呢?答案很简单,就是C(n,m)。如果一个整数m(0≤m≤n),C(n,m)是某一个质数p的倍数,那么这个m就是讨厌的数字,现在给定了p和n,求有多少个讨厌的数字。
Input
第一行是一个正整数n,(1≤n≤10100)。输入的第二行是一个质数p(1≤p≤107)。
Output
只有一行,表示讨厌的数字的个数。
Sample Input
6
2
2
Sample Output
3
HINT
30%的数据里,n≤1000; 100%的数据里,n≤10^100
第一次写lucas定理,觉得非常“机智”
将n,m分别分解p进制,发现如果某一位n[i]<m[i],则余数为0
注意,这里p非常大,所以一般数位dp中for一遍0到p是不可取的,要特殊判断关键点,对于[0,p-1]中转移相同的一起处理。
import sys; def deal(x,y): x=(x+y)%p; sys.stdin=open("input.txt","r"); n=int(raw_input()); p=int(raw_input()); a=[]; while (n): a.append(n%p); n/=p; for i in range(0,len(a)/2): a[i],a[len(a)-i-1] = a[len(a)-i-1],a[i]; dp = [[[0 for k in range(0,2)] for j in range(0,2)] for i in range(0,len(a)+2)]; dp[0][0][1]=a[0]; dp[0][0][0]=1; for i in range(1,len(a)): for j in range(0,2): for k in range(0,2): #print i,j,k; if (dp[i-1][j][k]==0):continue; if (k==0): dp[i][j][True] += dp[i-1][j][k]*a[i]; dp[i][j][False] += dp[i-1][j][k]; else: dp[i][j][True] += dp[i-1][j][k]*(a[i]+1); dp[i][True][True] += dp[i-1][j][k]*(p-a[i]-1); print (dp[len(a)-1][1][0]+dp[len(a)-1][1][1]);
by mhy12345(http://www.cnblogs.com/mhy12345/) 未经允许请勿转载
本博客已停用,新博客地址:http://mhy12345.xyz