ZOJ 3842 Cirno's Perfect Math Class (Kummer定理)

Cirno's Perfect Math Class
Time Limit: 2 Seconds      Memory Limit: 65536 KB 
"Minnaa ~ Cirno no Sansuu Kyoushitsu Hajimaruyo ~ "

Cirno's perfect math class is fashionable over the world. But now, sadly, it must be stopped for some reason. In the last class,N students attended, and each student gave a gift to Cirno. But the gifts are too many so that Cirno just want to takeK(K is non-negative) gifts away.

As we all know, Cirno loves the number ⑨. Assume there areP ways to take awayK gifts. IfP > 0 andP is a multiple of 9, Cirno will acceptK as an alternative plan. Now, Cirno want to know how many plans that she has to think over.

Input

The number of test cases T(integer, about 50) will be given in the first line. ThenT lines follow. and each line contains a non-negative integerN(N <= 10^1000).

Output

One line for each case, the answer.

Sample Input

  
  
3
5
1
9
0

Sample Output

  
  
0
6
3
Author: LIN, Hanzhao

Source: ZOJ Monthly, January 2015


题意:
给定n(n<=10^1000),求满足0<=k<=n且C(n,k)是9的倍数的k的个数。

分析:
考虑C(n,k)不是9的倍数的k的个数,分为两部分求解,
(1)C(n,k)不被3整除,

由Lucas定理知,若n的三进制表示为a[0]a[1]a[2]...a[s],则所求的个数为res=(a[0]+1)*(a[1]+1)*(a[2]+1)*...*(a[s]+1),
(2)C(n,k)被3整除但不被9整除,

这种情况比较麻烦,Lucas定理不能发挥作用,考虑使用更一般的Kummer定理,

根据Kummer定理,C(n,k)中3的幂次即为在三进制下n减去k时发生借位的次数,那么当C(n,k)恰被3整除时,n减k时恰好发生了一次借位,也就是说,有且仅有一个t,使得k的三进制表示的第t位严格大于n的第t位,且k的第t+1位严格小于n的第t+1位。枚举所有位置,注意到对每个位置计算贡献时,结果只有两个因式与res不同,如果不考虑大数运算的复杂度,可以O(1)计算贡献.

以上两种情况之和ans即为不满足条件的k的个数,输出n+1-ans即可,复杂度O((logn)^2)。


Kummer定理相关:

求Kummer定理知识_数学竞赛吧

库默尔定理_百度百科

关于组合数的几个整除问题_百度文库


代码:

import java.util.*;
import java.io.*;
import java.math.*;
public class Main
{
    static public void main(String[] args)
    {
        Scanner cin=new Scanner(System.in);
        int T=cin.nextInt();
        for(int ca=1;ca<=T;ca++)
        {
            BigInteger n=cin.nextBigInteger();
            String s=n.toString(3);
            BigInteger res=BigInteger.ONE;
            for(int i=0;i<s.length();i++)
            {
                res=res.multiply(BigInteger.valueOf(s.charAt(i)-'0'+1));
            }
            BigInteger ans=res;
            for(int i=1;i<s.length();i++)
            {
                ans=ans.add(res.divide(BigInteger.valueOf(s.charAt(i-1)-'0'+1))
                                .divide(BigInteger.valueOf(s.charAt(i)-'0'+1))
                                .multiply(BigInteger.valueOf(s.charAt(i-1)-'0'))
                                .multiply(BigInteger.valueOf('2'-s.charAt(i))));
            }
            System.out.println(n.subtract(ans).add(BigInteger.ONE));
        }
    }
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值