Math_4

45 篇文章 0 订阅

Math_4


大胖的超级数字


【问题描述】

大胖研究出了一种数字,名字叫做超级数。
这种数字有一个非常奇葩的属性,就跟大胖样的。
对于每一个超级数,其实都是对于给定的一个正整数 N 的阶乘的一种 B 进制表达,而且末尾恰好为 K 0
现在大胖想知道,对应于某一个正整数 N ,到底有多少个超级数?
答案对 1000000009 取模。


【输入】

输入文件名supernum.in。
一行两个正整数,分别为 N K


【输出】

输出文件名supernum.out。
一个整数,代表对应于 N K 的超级数的个数,无解请输出 0


【输入样例】

2 1


【输出样例】

1


【数据范围】

对于 20%的数据,保证有 n5
对于 50% 的数据,保证有 n1000000
对于 100% 的数据,保证有 n1015 K>N/500


Solution

x B 进制中末尾恰好有 K 0,那么 x 必能被 Bk 整除,且不能被 Bk+1 整除。

x=pt11×pt22××ptss (pi)
B=pq11×pq22××pqss (pi)

tikqi
0qitik

B 的每一位都有 (ti/k+1) 种可选择的方案。
ans=i=1s(tik+1)

所以我们只需要求出 ti 即可。
注意到,若 ti<k ,则 ti/k+1=1 ,并不影响答案,而 k 超大,所以我们要筛的素数不多,103 就够了。

这样我们就可以求出 Bk 绝对能够整除 x B 的个数。
同理,可以求出 Bk+1 绝对能够整除 x B 的个数。
相减即可。

至于如何在 n! 中求出素数的指数,就不用我说了吧,度娘欢迎你。


Code

#include <iostream>
#include <cstdio>

#define LL long long
#define MAXN 500
#define MOD 1000000009

using namespace std;

LL n,k;

LL prime[MAXN+10];
bool no_prime[MAXN+10];

LL work(LL x,LL y){

    LL ans=1;

    for(LL i=1;prime[i]<=x;i++){

        LL tmp=1,pre=x,cnt=0,t=0;
        do{
            tmp*=prime[i];
            cnt++;
            t+=(cnt-1)*(pre-x/tmp);
            pre=x/tmp;
        }while(tmp<=x);
        if(t/y==0)break;

        ans=(ans*(t/y+1)%MOD);
    }

    return ans;

}

int main(){

    freopen("supernum.in","r",stdin);
    freopen("supernum.out","w",stdout);

    for(LL i=2;i<=MAXN;i++){

        if(!no_prime[i])prime[++prime[0]]=i;

        for(LL j=1;prime[j]*i<=MAXN;j++){
            no_prime[prime[j]*i]=true;
            if(i%prime[j]==0)break;
        }

    }

    scanf("%lld%lld",&n,&k);

    printf("%lld\n",((work(n,k)-work(n,k+1))%MOD+MOD)%MOD);

    return 0;

}

大胖的神奇路径


【问题描述】

大胖最近在锻炼身体。(格式,格式,真的只是格式)
他家有一个无比巨大无比巨大的南北向跑道。
我们可以把这条跑道视作一个数轴,大胖家的位置在原点。
这天,大胖收到了大胖父母的指令,要求大胖今天要跑 N 次,每次 1Km,为了体现公平公正的原则,大胖有选择向南跑或者向北跑的权利,而且我们将这 N 次决策视作一个方案,对于任意两个方案如果有一次决策不同那么就视作两个不同的方案(规定对应每一次决策,往南跑为 1,往北跑为 0 ,则这 N 次决策顺次构成一个 01 序列,若两个 01 序列每一位对应相同,即视作相同方案)。
大胖最近虐现哥出的题目虐到无聊了,于是他决定,他要向南跑 X 次,而且每次大胖都希望自己不出现在自己家的北方。
他想知道,有多少种不同的方案满足自己的要求?答案对 1000000007 取模。


【输入】

输入文件名为road.in。
输入可能包含若干组数据,每个数据占一行,包含两个整数,分别为N和X。


【输出】

输出文件名为road.out。
对应输入中每组数据,输出一行一个整数代表满足要求的不同方案数。
若不存在合法的要求,则输出 0


【输入样例】

1 1


【输出样例】

1


【数据范围】

对于 20% 的数据,保证有 n10
对于 50% 的数据,保证有 n103
对于 70% 的数据,保证有 n106 ,而且数据只有一组。
对于 100% 的数据,保证有 n106 0XN ,数据组数不超过 1000


Solution

将向南走看作向右走,向北走看作像上走,就转化成了 网格 这道题。


Code

#include <iostream>
#include <cstdio>

#define LL long long
#define MAXN 1000000
#define MOD 1000000007

using namespace std;

LL power(LL x,LL y,LL p){

    if(y==0)return 1;
    if(y==1)return x%p;
    LL tmp=power(x,y/2,p);

    tmp=tmp*tmp%p;
    if(y&1)tmp=tmp*(x%p)%p;

    return tmp;

}

LL n,x;

LL jie[MAXN+10],ni[MAXN+10];

int main(){

    freopen("road.in","r",stdin);
    freopen("road.out","w",stdout);

    jie[0]=ni[0]=1;
    for(LL i=1;i<=MAXN;i++)jie[i]=jie[i-1]*i%MOD;

    ni[MAXN]=power(jie[MAXN],MOD-2,MOD);
    for(LL i=MAXN-1;i>=1;i--)ni[i]=ni[i+1]*(i+1)%MOD;

    while(scanf("%lld%lld",&n,&x)!=EOF){
        if(x<n-x){
            printf("0\n");
            continue;
        }
        printf("%lld\n",((jie[n]*ni[n-x]%MOD*ni[x]%MOD-jie[n]*ni[n-x-1]%MOD*ni[x+1]%MOD)%MOD+MOD)%MOD);
    }

    return 0;
}

大胖的中国象棋


【问题描述】

大胖最近在玩中国象棋。
他非常喜欢“車”这个棋子,因为读音和猪肉很像。
而且車能上能下,能左能右,是外出旅行,杀人放火之必需必备必不可少之良器。
现在有一个 N×N 的棋盘,大胖有 N 个車,这些車从 1 N 编号,其中第 i 个車不能放在第 i 行也不能放在第 i 列,请问有多少种摆放方法使得这些車互不冲突(意思就是这些車不在同一行且不在同一列)。
请输出方案数对一个数 M 的模值。


【输入】

输入文件名为chess.in
输入仅一行,包括两个正整数 N M


【输出】

输出文件名为chess.out
输出仅一行,表示方案数对 M 的模值。


【输入样例】

2 1000


【输出样例】

1


【数据范围】

对于 50% 的数据,保证有 n106
对于 100% 的数据,保证有 n1017 m<=106


Solution

考虑每一个車,设它的坐标为 (x,y)
1 ~ n 的所有的车的 x 坐标为 1 ~ n 的一个排列,且第 i 辆车的 x 不能为 i
所以上错排公式,Di=(i1)(Di1+Di2)
同理, y 坐标也是如此。
所以 ans=D2n

打表发现,答案每 m <script type="math/tex" id="MathJax-Element-1047">m</script> 一循环。


Code

#include <iostream>
#include <cstdio>

#define LL long long

using namespace std;

LL n,m;
LL s[1000010];

int main(){

    freopen("chess.in","r",stdin);
    freopen("chess.out","w",stdout);

    scanf("%lld%lld",&n,&m);

    s[1]=0;s[2]=1;

    n=(n-1)%m+1;

    for(LL i=3;i<=n;i++)
        s[i]=((i-1)%m)*((s[i-1]+s[i-2])%m)%m;

    printf("%lld\n",s[n]*s[n]%m);

    return 0;
}
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值