您的位置:首页 > 其它

数学测试4

2016-06-21 10:11 239 查看

大胖的超级数字

问题描述 Description

大胖研究出了一种数字,名字叫做超级数。

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

输入描述 Input Description

一行两个正整数,分别为 N,K 。

输出描述 Output Description

一个整数,代表对应于 N 和 K 的超级数的个数,无解请输出 0。

输入样例 Sample Input

2 1

输出描述 Sample Output

1

数据范围及提示 Data Size & Hint

对于 20% 的数据,保证有 n≤5。

对于 50% 的数据,保证有 n≤1000000。

对于 100% 的数据,保证有 n≤1015,K>N500 。

分析 I Think

B 进制表达,末尾恰好为 K 个 0,也就是 BK∣(n!),BK+1∤(n!) ,设 B=∏ri=1pqii,(n!)=∏ri=1ptii,∀pi∈prime.因为 ti≥K∗qi,所以 1≤qi≤⌊tiK⌋,所以每一个 qi 有 ⌊tiK⌋+1 种取值,故 ans=∏ri=1(⌊tiK⌋+1),当然可能存在 BK+1∣(n!) 的情况,所以还要减去 ∏ri=1(⌊tiK+1⌋+1)

代码 Code

#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;

typedef long long LL;

const LL Mod = 1000000009;
const int Size = 1000;

int prime[Size];
LL p[Size];
bool no_prime[Size];
LL N,K;

void get_prime(int);

int main(){

get_prime(Size-1);

scanf("%lld%lld",&N,&K);

do{
++p[0];
LL r = N;
while(r > 0){
p[p[0]] += r/prime[p[0]];
r /= prime[p[0]];
}
}while(p[p[0]] >= K);

LL re=1,res=1;
for(int i=1;i<p[0];++i)
re = re*(p[i]/K+1)%Mod;
for(int i=1;i<p[0];++i)
res = res*(p[i]/(K+1)+1)%Mod;

printf("%lld",(re+Mod-res)%Mod);

return 0;

}

void get_prime(int x){

for(int i=2;i<=x;++i){
if(!no_prime[i])
prime[++prime[0]] = i;
int t=i<<1,j=1;
while(t<=x && j<=prime[0]){
no_prime[t] = true;
if(i%prime[j] == 0)
break;
t = i*prime[++j];
}
}

}


大胖的神奇路径

问题描述 Description

大胖最近在锻炼身体。(格式,格式,真的只是格式)

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

输入描述 Input Description

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

输出描述 Output Description

对应输入中每组数据,输出一行一个整数代表满足要求的不同方案数。

若不存在合法的要求,则输出 0 。

输入样例 Sample Input

1 1

输出描述

1

数据范围及提示 Data Size & Hint

对于 20% 的数据,保证有 n≤10 。

对于 50% 的数据,保证有 n≤103。

对于 70% 的数据,保证有 n≤106 ,而且数据只有一组。

对于 100% 的数据,保证有 n≤106 , 0≤X≤N,数据组数不超过 1000 。

分析 I Think

大胖不希望出现在家的北方,也就是 01 串的任意一位都有之前的(含当前位) 1 的个数大于等于 0 的个数,所以当 N>2X 时不存在合法的要求,当 N=7,X=4 时 1010101 是一个合法的序列,但 1001101 是一个不合法的序列,因为在第三位1 的个数小于等于 0 的个数,我们将第三位及其之前的 01 取反 ,得到 0111101 ,在这个序列中,存在 X+1 个 1 ,而每一个这要的序列都可以将前面第一次 1 大于 0 的地方及之前的再取反就可以得到一个含 X 个 1 的不合法序列,所以 ans=CXN−CX+1N

代码

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

typedef long long LL;

const LL Mod = 1000000007;
const int Size = 1000001;

LL f[Size],g[Size];

LL pow(LL,LL);

int main(){

f[0] = f[1] = 1;
for(int i=2;i<Size;++i)
f[i] = f[i-1]*i%Mod;

g[Size-1] = pow(f[Size-1],Mod-2);
for(int i=Size-2;i>=0;--i)
g[i] = g[i+1]*(i+1)%Mod;

int n,x;

while(scanf("%d%d",&n,&x)!=EOF){

if(n > (x<<1))
puts("0");
else
printf("%lld\n",(f
*g[x]%Mod*g[n-x]%Mod-f
*g[x+1]%Mod*g[n-x-1]%Mod+Mod)%Mod);

}

return 0;

}

LL pow(LL x,LL y){

LL ans=1;
while(y){
if(y&1)
ans = ans*x%Mod;
x=x*x%Mod;
y >>= 1;
}

return ans;

}


大胖的中国象棋

问题描述 Description

大胖最近在玩中国象棋。

他非常喜欢“車”这个棋子,因为读音和猪肉很像。而且車能上能下,能左能右,是外出旅行,杀人放火之必需必备必不可少之良器。

现在有一个 N∗N 的棋盘,大胖有 N 个車,这些車从 1 到 N 编号,其中第 I 个車不能放在第 I 行也不能放在第 I 列,请问有多少种摆放方法使得这些車互不冲突(意思就是这些車不在同一行且不在同一列)。请输出方案数对一个数 M 的模值。

输入描述 Input Description

输入仅一行,包括两个正整数 N 和 M

输出描述 Output Description

输出仅一行,表示方案数对 M 的模值。

输入样例 Sample Input

2 1000

输出样例 Sample Output

1

数据范围及提示 Data Size & Hint

对于 50% 的数据,保证有 n≤106。

对于 100% 的数据,保证有 n≤1017 , m≤106 。

分析 I Think

每一个車的位置 (xi,yi) ,都有 xi,yi≠i ,所以我们将 xi,yi 错排,最后答案就是两次错排的方案之积。错排的利用容斥原理实现

ans=∑i=1n(−1)iCin(n−i)! mod m=∑i=1n(−1)in!i!(n−i)!(n−i)! mod m=∑i=1n(−1)in!i! mod m=∑i=1n(−1)i[n(n−1)...(i+1)] mod m

当 [n(n−1)...(i+1)] mod≡0(mod m) 时 一定存在 [n(n−1)...(i+1)i] mod≡0(mod m) ,所以只需要枚举 i 枚举到 [n(n−1)...(i+1)] mod≡0(mod m) 时即可。

代码 Code

#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;

typedef long long LL;

const LL s[] = {1,-1};

LL n,m;

int main(){

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

LL ans = s[n&1];
for(LL i=n-1,p=n%m;i>=0&&p;p=p*((i--)%m)%m)
ans = (ans+s[i&1]*p)%m;

printf("%lld\n",ans*ans%m);

return 0;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  数学