• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
mhy12345
博客园    首页    新随笔    联系   管理    订阅  订阅

bzoj 1902: Zju2116 Christopher lucas定理 && 数位DP

1902: Zju2116 Christopher

Time Limit: 1 Sec  Memory Limit: 64 MB
Submit: 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

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

posted @ 2015-04-28 13:51  mhy12345  阅读(386)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3