您的位置:首页 > 其它

2017.9.22 模拟考试 解题报告

2017-09-22 20:24 176 查看

2017.9.22 模拟考试 解题报告

T1

T1写写看看,一会就发现规律了,然后,除法分块,徐队说:“开莫比乌斯函数,sigma什么的一定会考除法分块”,这道题在洛谷上就叫 约数和

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define LL long long
inline LL calc(int n){
LL l=1,r,a,ret=0;
for(;l<=n;l=r+1){
a=n/l;//l,r 是区间的左右端点  a代表连续的等差的序列的被用次数
r=n/a;
ret+=(r-l+1)*(r+l)*0.5*a;
}
return ret;
}

int main(){
freopen("A.in","r",stdin);
freopen("A.out","w",stdout);
int x,y;
cin>>x>>y;
cout<<calc(y)-calc(x-1);
fclose(stdin);fclose(stdout);
return 0;
}


等差序列求和公式

Sn=(a1+an)*n*0.5;

再详细说明一下a含义

举个栗子:

X=1,Y=12,Ans=sigma f(i)

1 2 3 4 5 6 7 8 9 10 11 12

12 6 4 3 2 2 1 1 1 1 1 1

第一个等差数列是l=1,r=1,a=12,意思就是说1作为因数贡献了12次

5、6下面对应都是2

5、10、6、12

该等差数列用了两次,恩,应该说的很明白了,当i越大的时候等差数列的长度越长,效率越高。

T2

UVa11440 原题

思路:ϕ(m!)表示小于m!并与m!互质的个数,而与m!互质的个数,他的质因子肯定不包含1-m,因此就是满足条件的。然后对于这题而言,则是要求n!中,不与m!互质的个数,答案取模100000007

求kn中与n互质的个数,答案为kϕ(n)。

ϕ(n)表示1-n中与n互质的个数,那么由此考虑[n + 1, 2n], [2n + 1, 3n]…这每个区间中的每个数字都等于1-n中数字加上kn,对于原来就与n不互质的个数,加上n仍会有一个质因子重复,所以仍然不行,那么对于原来互质的数x,gcd(x, n) = 1,那么可知gcd(x + kn, n) = 1,仍然是互质的,所以每隔n的区间与n互质的个数是相同的,所以答案kϕ(n)

所以对于这道题目,答案就变成了n!/m!ϕ(m!),那么问题只剩下如何求ϕ(m!)。

m!=1*2*3*….*m 所以对m!的阶乘质因数分解得到的因子只能是1-m中的质数。

已知ϕ(n)求法为n∗(1−1/p1)∗(1−1/p2)….(1−1/pn) (p为n的质因子),因此对于m!而言,分子为m!,分母为1 - m所有质数的(1−1/p)之乘积

到这里答案就可以求了,把m!消掉,得到n!/∏(1−1/pi)mod1000000007,先预处理那些表,每次去计算即可

#include<cstdio>
using namespace std;
#define MAXN 10000001
#define Mod 100000007
#define LL long long
int prime[664580],cnt;
bool v[MAXN];
LL phifac[MAXN];
int main(){
freopen("B.in","r",stdin);
freopen("B.out","w",stdout);
int n,m;
scanf("%d%d",&n,&m);
for(int i=2;i<MAXN;++i){
if(!v[i]) prime[++cnt]=i;
for(int j=1;j<=cnt;++j){
if(i*prime[j]>=MAXN) break;
v[i*prime[j]]=true;
if(i%prime[j]==0) break;
}
}
LL ans=0;
phifac[1]=1;
for(int i=2;i<=m;++i)
if(!v[i]) phifac[i]=phifac[i-1]*(i-1)%Mod;
else phifac[i]=phifac[i-1]*i%Mod;
ans=phifac[m];//现在ans就是phi(m!)
for(register int i=m+1;i<=n;++i) ans=ans*i%Mod; //Ans乘上n!/m!倍
printf("%I64d\n",ans-1);
return 0;
}


上篇代码注释:phifac[m]表示m!的欧拉函数值

解释一下我的递推式:

 最原始的方程phi((m-1)!)=(m-1)!((P1-1)/P1) ….((Pk-1)/Pk)

 当m是质数时,phi(m!)= m*(m-1)! ((P1-1)/P1) ….((Pk-1)/Pk)((m-1)/m),中间那一块就是phi((m-1)!),==> phi(m!)= m*phi((m-1)!)((m-1)/m),两个蓝色的m再约个分,就得了上面代码里的样子了

 当m不是质数的时候,phi(m!)= m*(m-1)! ((P1-1)/P1) ….((Pk-1)/Pk),【因为m不是质数嘛,m肯定可以用p1、p2、、、、pk中的几个质因子表示】,然后中间一坨还是phi((m-1)!),于是乎又有了上面代码中的样子。。

T3

UVa6396 原题

网上有好几份题解是反素数,看了看没看懂,还是看徐队的搜索吧。

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define LL long long
int prime[25]={0,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71};
LL ans,n,C[70][70];
void solve(int num,int lim,LL tot,LL now,int last){
if(now>ans) return ;
if(tot==n) { ans=now; return ; }
if(tot>n || num>20) return ;
LL t=1;
for(int i=1;i<=lim;++i){
t*=prime[num];
if(now>=ans/t) return;
solve(num+1,i,tot*C[last+i][i],now*t,last+i);
}
}

int main(){
freopen("C.in","r",stdin);
freopen("C.out","w",stdout);
C[0][0]=1;
for(int i=1;i<70;++i){
C[i][0]=1;
for(int j=1;j<=i;++j)
C[i][j]=C[i-1][j]+C[i-1][j-1];
}
scanf("%I64d",&n);
if(n==1) { printf("1 2\n"); return 0; }
ans=(LL)1<<60;
solve(1,63,1,1,0);
printf("%I64d\n",ans);
return 0;
}


这道题当时在考场上退出了反着做的正解,哈哈哈,没什么软用。

从最小的质数开始枚举选几个

假设前i-1个种质数用了k个,有Np种方案,第i种质数选a个,

那么前i种质数的方案就有Np*C[k+a][a]

可以理解原来有k个位置,又加了a个位置,有a个数可以放在任意位置

所以前i种的每一种方案都变成C[k+a][a]种

枚举每个质数选几个时,如果上一个质数选了k个,那么这一个质数最多选k个

假设这个质数选了k+1个,那么显然上一个质数选k+1个,这个选k个更优,就是说大质数陪小底数,小大,大小。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  考试 数学