数学测试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; }