• 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
  • 相关阅读:
    webdriver---API---(java版) the fifth part
    【CSP-S2019模拟】题解
    【CSP-S2019模拟】题解
    【洛谷P5113】—魔女的夜宴Sabbat of the witch(分块+基数排序)
    【Codeforces 666 E】—Forensic Examination(广义Sam+线段树合并)
    【洛谷P4081】【USACO17DEC】—Standing Out from the Herd(广义Sam)
    【洛谷P4451】整数的lqp拆分(生成函数)
    【CSP-S 2019模拟】题解
    【Codeforces 335 E】—Counting Skyscrapers
    【Codeforces 793 G】—Oleg and chess(线段树优化建图+最大流)
  • 原文地址:https://www.cnblogs.com/16er/p/5162302.html
Copyright © 2020-2023  润新知