导航

HDNOIP201405杨辉三角

Posted on 2016-01-27 10:01  POOH1DROSE  阅读(398)  评论(0编辑  收藏  举报

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