zoukankan      html  css  js  c++  java
  • HDNOIP201405杨辉三角

    2016.1.27

    试题描述

        杨辉三角是形如如下的数字三角形:

            1

         1    1

       1   2    1

    ……

    现在想求出杨辉三角第N行的N个数中,有多少个数能被给定的质数p整除。
    输入
    一行两个空格隔开的整数N和p
    输出
    输出一个整数,表示第N行能被给定的质数p整除的个数
    输入示例
    3 2
    输出示例
    1
    其他说明
    对于60%的数据,N≤30,p≤1000,对于80%的数据,N≤1000,p≤1000,对于100%的数据,N≤〖10〗^9,p≤1000

    首先知道是卢卡斯定理 和 组合数取模

    然后就一个一个试呗

    #include<iostream>
    using namespace std;
    int a[1005],e,ans;
    int main()
    {
        int n,p,b,ct;
        scanf("%d%d",&n,&p);
        b=n-=1;
        while(b)
        {
            a[++e]=b%p;
            b/=p;
        }
        for(int i=0;i<=n;i++)
        {
            b=i;ct=1;
            while(b)
            {
                if(b%p>a[ct]) {ans+=1;break;}
                else {ct++;b/=p;}
            }
        }
        printf("%d",ans);
    }
    View Code

    然后果断TLE

    然后根据杨辉三角的对称性,砍一半

    #include<iostream>
    using namespace std;
    int a[1005],e,ans;
    int main()
    {
        int n,p,b,ct;
        scanf("%d%d",&n,&p);
        b=n-=1;
        while(b)
        {
            a[++e]=b%p;
            b/=p;
        }
        for(int i=0;i<(n+1)/2;i++)
        {
            b=i;ct=1;
            while(b)
            {
                if(b%p>a[ct]) {ans+=1;break;}
                else {ct++;b/=p;}
            }
        }
        ans*=2;
        if(n+1&1)
        {
            b=n/2;ct=1;
            while(b)
            {
                if(b%p>a[ct]) {ans+=1;break;}
                else {ct++;b/=p;}
            }
        } 
        printf("%d",ans);
    }
    View Code

    然并卵,依旧TLE

    于是机智的我想到了构造

    还想到了状态压缩

    就是二进制某一位为1表示构造的数在p进制下该位上比n在对应位上大

    #include<iostream>
    using namespace std;
    int a[105],e,ans;
    int main()
    {
        int n,p,b,ct;
        scanf("%d%d",&n,&p);
        b=n-=1;
        while(b)
        {
            a[++e]=b%p;
            b/=p;
        }
        for(int t = e-1 ; t >= 1 ; t-- )
        {
            for(int i = ( 1 << t ) - 1 ; i >= 1 ; i-- )
            {
                b=i;ct=a[t+1];
                for(int j = t-1 ; j >= 0; j-- )
                {
                    if(1<<j&b) ct*=p-1-a[j+1];
                    else ct*=a[j+1]+1;
                }
                ans+=ct;
            }
        }
        printf("%d",ans);
    }
    View Code

    AC后激动的我瞬间觉得我有做神犇的潜质

    但我发现其他人的代码都特短。。。

    我方了

    冷静后,发现我傻*了

    明明可以反着算。。。要知道根据卢卡斯定理构造模p不等于0的数有多简单。。。

    看了代码瞬间就懂的

    AC代码:

    #include<iostream>
    using namespace std;
    int e,ans=1;
    int main()
    {
        int n,p,b;
        scanf("%d%d",&n,&p);
        b=n-1;
        while(b)
        {
            ans*=b%p+1;
            b/=p;
        }
        printf("%d",n-ans);
    }
    View Code
  • 相关阅读:
    小程序(1)
    手机端放在线条中间的标题
    不定长度导航的两端对齐
    扇形导航菜单
    个性搜索框
    javascript数组原型方法
    jquery插件开发的demo
    监听表单中的内容变化
    mui中的关闭页面的几种方法
    css之伪类选择器:before :after(::before ::after)
  • 原文地址:https://www.cnblogs.com/16er/p/5162302.html
Copyright © 2011-2022 走看看