您的位置:首页 > 其它

几道数学题

2014-05-13 20:52 330 查看

从给定的[a,b]区间选出一个数x,从[c,d]区间选出数y,问有多少对(x,y)满足(x+y)%p=m

思路:对于a<=x<=b,c<=y<=d.

满足条件的结果为ans=f(b,d)-f(b,c-1)-f(a-1,d)+f(a-1,c-1)。

而函数f(a,b)是计算0<=x<=a,0<=y<=b满足条件的结果。这样计算就很方便了。

LLgcd(LLx,LLy){
returny==0?x:gcd(y,x%y);
}

LLp,m;
LLans(LLa,LLb){
if(a<
0||b<0)return0;
LLs=0;
LLma=a%p,mb=b%p;
s+=(a/p)*(b/p)*p;
s+=(ma+1)*(b/p)+(mb+1)*(a/p);
if(ma>m){
s+=min(m,mb)+1;
LLt=(p+m-ma)%p;
if(t<=mb)s+=mb-t+1;
}
else{
LLt=(p+m-ma)%p;
if(t<=mb)s+=min(mb-t+1,m-t+1);
}
returns;
}

intmain(){
intt,T=
1;
LLa,b,c,d,s,g,f;
cin>>t;
while(t--){
cin>>a>>b>>c>>d>>p>>m;
s=ans(b,d)-ans(c-1,b)-ans(a-1,d)+ans(a-1,c-1);
f=(d-c+1)*(b-a+1);
g=gcd(f,s);
printf("Case#%d:%I64d/%I64d\n",T++,s/g,f/g);
}
return
0;
}

路径f:由A到D;g:由B到C的路径。沿坐标轴正方向走,f,g不能有交集。求路径对(f,g)总数

A(0,0),B(p,0),C(m,q),D(m,n);

因为(f,g)不相交数=(f,g)总数-(f,g)相交数;

总数:c(m+n,m)*c(m-p+q,q);

相交数:c(m+q,m)*c(m-p+n,n);

constLLmod=100000007;

LLexgcd(LLa,LLb,LL&x,LL&y){

if(b==0){

x=1;

y=0;

returna;

}

LLg=exgcd(b,a%b,x,y);

LLt=x;

x=y;

y=t-(a/b)*y;

returng;

}


LLinverse(LLn){

LLx,y;

exgcd(n,mod,x,y);

return(x%mod+mod)%mod;

}


LLC(LLn,LLm){

LLu=1,v=1;

for(LLi=0;i<m;i++){

u=u*(n-i)%mod;

v=v*(i+1)%mod;

}

returnu*inverse(v)%mod;

}


intmain(){

LLs,m,n,p,q;

while(cin>>m>>n>>p>>q){

s=C(m+n,n)*C(m+q-p,q)%mod;

s-=C(m+q,m)*C(m+n-p,n)%mod;

s=(s%mod+mod)%mod;

cout<<s<<endl;

}

return0;

}


要求满足的m=a^3+b^3=(a+b)(a2-ab+b2)的(a,b)组合。

令t=x1+x2,则t一定是m的约数,所以应枚举m的所有约数。

然后可以得到

t=x1+x2

n/t=x1^2-x1*x2+x2^2;

=t*t–3x1*x2

ðx1*x2=(t*t-n/t)/3=m;

有韦达定理x1,x2为二次方程x^2–mx+t=0的2正整数根

再就是注意范围要用unsignedlonglong。

typedefunsignedlonglongll;

constllM=3000001;

intcnt,num,cn;

llprime[M],p[100],e[100];

boolf[M];

lln;

voidmake(){

cnt=0;

for(inti=2;i<M;i++){

if(!f[i])prime[cnt++]=i;

for(intj=0;j<cnt&&i*prime[j]<M;j++){

f[i*prime[j]]=1;

if(i%prime[j]==0)break;

}

}

}

voidfac(llm){

num=0;

for(lli=0;i<cnt&&(ll)prime[i]*prime[i]<=m;i++){

if(m%prime[i]==0){

p[num]=prime[i];

llj=1;

m/=prime[i];

while(m%prime[i]==0){

j++;

m/=prime[i];

}

e[num++]=j;

}

}

if(m>1){

p[num]=m;

e[num++]=1;

}

}

llispw2(lla){

llb=sqrt(1.0*a);

if((ll)b*b==a)returnb;

returnM;

}


map<ll,ll>answer;

map<ll,ll>::iteratorit;

voidis(llt){

llx1,x2;

llp=n/t;

lla=t*t-p;

if(a>0&&a%3!=0)return;

llm=a/3;

llb=t*t-4*m;

if(b<0)return;

llc=ispw2(b);

if(c==M)return;

if((t+c)%2==0){

x1=(t+c)/2;

x2=t-x1;

if(x1>x2)swap(x1,x2);

if(x1>0&&x1<t&&x2>0&&x2<t&&answer.find(x1)==answer.end()){

answer[x1]=x2;

}

}

}


llPow(llx,lly){

lls=1;

for(;y;y>>=1,x*=x){

if(y&1)s*=x;

}

returns;

}


voiddfs(intid,lls){

is(s);

if(id>=num)return;

for(inti=0;i<=e[id];i++)

dfs(id+1,(ll)s*Pow(p[id],i));

}


intmain(){

make();

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

fac(n);

cn=0;

answer.clear();

dfs(0,1);

printf("%d",answer.size());

for(it=answer.begin();it!=answer.end();it++)

printf("(%llu,%llu)",it->first,it->second);

printf("\n");

}

return0;

}


一门课的书有N章内容要复习,每天可以复习一章,但是有M个限制条件:在第D[i]天中无法复习第C[i]章,问不同的复习方案数

容斥原理,不考虑约束条件,则一共有N!种复习方案,然后减去刚好触发一个约束条件的方案数,加上刚好触发两个约束条件的方案数,减去刚好触发三个的……依此类推

另外注意一点,输入中可能包含重复的约束条件,要先去重再算容斥,否则会得到错误的结果

题意抽象出来就是在n*n的棋盘中加了m个禁位,放置n个棋子,每两个棋子不在同一行同一列,问有多少中放置方式?

trick:

M个禁位中有相同坐标的点。

解法:利用有禁位的排列的公式(容斥原理):

n!-r1*(n-1)!+r2*(n-2)!-r3*(n-3)!+..........

ri指在禁区中选i个位置的方案数。

由于m的值较小,可直接dfs暴力求方案数。


constLLmod=55566677;

intx[28],y[28];

LLp[60];

boolvisx[60],visy[60];

intn,m;

LLs;


voiddfs(intcnt,intid,intf){

s=(s+p[n-cnt]*f)%mod;

s=(s+mod)%mod;

for(inti=id+1;i<m;i++){

if(!visx[x[i]]&&!visy[y[i]]){

visx[x[i]]=visy[y[i]]=1;

dfs(cnt+1,i,-f);

visx[x[i]]=visy[y[i]]=0;

}

}

}


intmain(){

inti,j;

p[0]=p[1]=1;

for(i=2;i<60;i++)p[i]=p[i-1]*i%mod;

while(cin>>n>>m){

for(i=0;i<m;i++)scanf("%d%d",&x[i],&y[i]);

for(i=0;i<m;i++){

for(j=i+1;j<m;j++){

if(x[i]==x[j]&&y[i]==y[j]){

swap(x[j],x[m-1]);

swap(y[j],y[--m]);

}

}

}

memset(visx,0,sizeof(visx));

memset(visy,0,sizeof(visy));

s=0;

for(i=0;i<m;i++){

visx[x[i]]=visy[y[i]]=1;

dfs(1,i,1);

visx[x[i]]=visy[y[i]]=0;

}

s=(p
-s)%mod;

s=(s+mod)%mod;

cout<<s<<endl;

}

return0;

}

限位排列
一门课的书有N章内容要复习,每天可以复习一章,但是第i章不能在第i天或第i+1天复习(最后一章则对应最后一天和第一天),问不同的复习方案数,
递推公式如下:

intmain(){

f[0]=f[3]=1,f[1]=f[2]=0,f[4]=2;

intn;

for(n=5;n<=maxn;n++){

if(n%2)

f
=(f[n-1]*n%mod+(f[n-2]*n%mod+4)*inverse(n-2))%mod;

else

f
=(f[n-1]*n%mod+(f[n-2]*n%mod-4)*inverse(n-2))%mod;

}

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

printf("%lld\n",f
);

}

return0;

}


题意:求第k个斐波那契素数对应的斐波那契数列及其之后的值%x==0的最小的斐波那契数值,(%m),
zoj

数据范围:(1<=k<=10^6),(3<=X<=100),(10<=M<=10^6)

解题思路:

斐波那契数列的特性:(0,1,1,2,3,5,8...)

1、gcd(fib(n),fib(m))=fib(gcd(n,m))

2、如果fib(k)能被x整除,则fib(k*i)都可以被x整除。

3、f(0)+f(1)+f(2)+…+f(n)=f(n+2)-1

4、f(1)+f(3)+f(5)+…+f(2n-1)=f(2n)

5、f(2)+f(4)+f(6)+…+f(2n)=f(2n+1)-1

6、[f(0)]^2+[f(1)]^2+…+[f(n)]^2=f(n)·f(n+1)

7、f(0)-f(1)+f(2)-…+(-1)^n·f(n)=(-1)^n·[f(n+1)-f(n)]+1

8、f(m+n)=f(m-1)·f(n-1)+f(m)·f(n)

9、[f(n)]^2=(-1)^(n-1)+f(n-1)·f(n+1)

10、f(2n-1)=[f(n)]^2-[f(n-2)]^2

11、3f(n)=f(n+2)+f(n-2)

12、f(2n-2m-2)[f(2n)+f(2n+2)]=f(2m+2)+f(4n-2m)[n〉m≥-1,且n≥1]

还有一个结论:

计算(a/b)%c其中b能整除a

如果b与c互素,则(a/b)%c=a*b^(phi(c)-1)%c

如果b与c不互素,则(a/b)%c=(a%bc)/b

对于b与c互素和不互素都有(a/b)%c=(a%bc)/b成立

斐波那契素数的定义:(2,3,5,13,89...)

对于斐波那契数列的第i个元素s[i],如果gcd(s[i],s[j])==1(1<=j<i),那么s[i]是一个斐波那契素数。

斐波那契素数的特性(可根据斐波那契数列求出斐波那契素数):

对于斐波那契数列(0,1,1,2,3,5,8...),下标从0开始,下标为3,4,5,7,11,13...的数就是斐波那契素数。

即除了前两个外,斐波那契数列的素数下标对应的就是斐波那契素数,而如果下标不是素数,那么对应的也不是斐波那契素数。

所以这一题就先筛出斐波那契素数下标(3,4,5,7,11,13...),然后就可以知道第k个斐波那契素数对应的斐波那契数列的下标,

根据矩阵快速幂计算出斐波那契数值,判断是否%x==0,如果不是就继续找下一个,直到找到为止。最后a/x%m=(a%(x*m))/x

typedeflonglongLL;

constintmaxn=15500000;

intprimesize;

intprime[maxn+8];

boolis[maxn+8];

voidmake(){

primesize=0;

memset(is,0,sizeof(is));

for(inti=2;i<=maxn;i++){

if(!is[i])prime[++primesize]=i;

for(intj=1;j<=primesize&&prime[j]*i<=maxn;j++){

is[prime[j]*i]=1;

if(i%prime[j]==0)break;

}

}

prime[1]=3;

prime[2]=4;

}


LLmod;

structMat{

LLx[3][3];

Mat(){

x[1][1]=0,x[1][2]=0;

x[2][1]=0,x[2][2]=0;

}

Mat(int){

x[1][1]=1,x[1][2]=0;

x[2][1]=0,x[2][2]=1;

}

Mat(LLa11,LLa12,LLa21,LLa22){

x[1][1]=a11,x[1][2]=a12;

x[2][1]=a21,x[2][2]=a22;

}

};


Matoperator*(MatA,MatB){

Mats;

for(inti=1;i<=2;i++){

for(intj=1;j<=2;j++){

for(intk=1;k<=2;k++){

s.x[i][j]+=A.x[i][k]*B.x[k][j];

s.x[i][j]%=mod;

}

}

}

returns;

}


Matoperator^(Matx,inty){

Mats(1);

for(;y;y>>=1){

if(y&1)s=s*x;

x=x*x;

}

returns;

}


constMatF(1,1,1,0);


intmain(){

make();

LLk,x,m;

inti,t;

MatA;

cin>>t;

while(t--){

scanf("%lld%lld%lld",&k,&x,&m);

intid=prime[k];

mod=x;

for(i=id;;i++){

A=F^(i-1);

if(A.x[1][1]%x==0)break;

}

mod=x*m;

A=F^(i-1);

printf("%lld\n",A.x[1][1]/x);

}

return0;

}


关于方程a^x=1(modm)的最小x解

定理:

设gcd(a,m)=1,必有正整数x,使得a^x=1(modm),且设满足等式的最小正整数为x0,必满足x0|phi(m).注意m>1.

否则如果gcd(a,m)!=1,则方程a^x=1(modm)没有解。

constintmaxn=70000;
intprime[maxn];
intprimesize;
boolis[maxn+10];
voidmake(){
memset(is,0,sizeof(is));
primesize=0;
for(inti=2;i<=maxn;i++){
if(!is[i])prime[primesize++]=i;
for(intj=0;j<primesize&&i*prime[j]<=maxn;j++){
is[i*prime[j]]=1;
if(i%prime[j]==0)break;
}
}
}

intphi(intn){
intm=sqrt(0.5+n);
ints=n;
for(inti=0;i<primesize&&n!=1&&prime[i]<=m;i++){
if(n%prime[i]==0){
s=s-s/prime[i];
while(n%prime[i]==0)n/=prime[i];
}
}
if(n!=1)s=s-s/n;
returns;
}

intgcd(intx,inty){
returny==0?x:gcd(y,x%y);
}

structFac{
intx;
ints;
Fac(){}
Fac(int_x,int_s):x(_x),s(_s){}
}h[208];
vector<int>factor;
vector<int>::iteratorit;
intfacsize;
voidgetfac(intn){
intm=sqrt(0.5+n),t;
facsize=0;
for(inti=0;i<primesize&&n!=1&&prime[i]<=m;i++){
if(n%prime[i]==0){
t=0;
while(n%prime[i]==0){t++;n/=prime[i];}
h[facsize++]=Fac(prime[i],t);
}
}
if(n!=1)h[facsize++]=Fac(n,1);
}

intPow(intx,inty){
ints=1;
for(;y;y>>=1,x*=x){
if(y&1)s*=x;
}
returns;
}

intPow(intx,inty,intm){
ints=1;
for(;y;y>>=1,x*=x,x%=m){
if(y&1)s*=x,s%=m;
}
returns;
}

voiddfs(intid,intn){
if(id==facsize){
factor.push_back(n);return;
}
for(inti=0;i<=h[id].s;i++)
dfs(id+1,n*Pow(h[id].x,i));
}

voidgetfactor(intn){
factor.clear();
getfac(n);
dfs(0,1);
sort(factor.begin(),factor.end());
}

intanswer(inta,intm){
getfactor(phi(m));
for(it=factor.begin();it!=factor.end();it++){
if(Pow(a,*it,m)==1)return*it;
}
}

intmain(){
make();
intn,i,ph;
while(scanf("%d",&n)!=EOF){
if(n==1||gcd(2,n)!=1){
printf("2^?mod%d=1\n",n);
continue;
}
printf("2^%dmod%d=1\n",answer(2,n),n);
}
return0;
}


写法2

LLphi(LLn){
LLs=n;
LLm=(LL)sqrt(0.5+n);
for(LLi=2;n!=1&&i<=m;i++){
if(n%i==0){
s=s-s/i;
while(n%i==0)n/=i;
}
}
if(n!=1)s=s-s/n;
returns;
}

LLgcd(LLx,LLy){
returny==0?x:gcd(y,x%y);
}

vector<LL>factor;
vector<LL>::iteratorit;

voidgetfactor(LLn){
factor.clear();
LLm=(LL)sqrt(0.5+n);
for(LLi=1;i<=m;i++){
if(n%i==0){
factor.push_back(i);
if(i*i!=n)factor.push_back(n/i);
}
}
sort(factor.begin(),factor.end());
}

LLPow(LLx,LLy,LLm){
LLs=1;
for(;y;y>>=1,x*=x,x%=m){
if(y&1)s*=x,s%=m;
}
returns;
}

LLanswer(LLa,LLm){
getfactor(phi(m));
for(it=factor.begin();it!=factor.end();it++){
if(Pow(a,*it,m)==1)return*it;
}
}

intmain(){
LLn,i;
while(scanf("%I64d",&n)!=EOF){
if(n==1||gcd(2,n)!=1){
printf("2^?mod%lld=1\n",n);
continue;
}
printf("2^%I64dmod%I64d=1\n",answer(2,n),n);
}
return0;
}


题目大意是:在一个平面上有N个点,每个点的坐标已经给出,现在要求在X轴上找一个点,使得这个点到所有点中最大的距离最小。

分析:我们设这个点为X0,所求的距离为F(x),那么对于所有的X<X0和X>X0都有F(x)>ans,即实际上这个函数是已X0为最小值,两边

都是单调递增或者递减的,因此我们可以三分查找找出这个最值的坐标。总复杂度O(n*logn).

constdoubleEPS=1e-9;

constintmaxn=50008;
intn;
doublex[maxn],y[maxn];

doublef(doublenx){
doubles=0,d;
for(inti=1;i<=n;i++){
d=sqrt(y[i]*y[i]+(x[i]-nx)*(x[i]-nx));
if(s<d)s=d;
}
returns;
}
//三分对凹(凸)函数判断最小(大)值,此题是求最小值。
//不要求左l右r值的大小比较,即(L<R或L>=R)都可
doubletri_search(doublel,doubler){
doubleMid,Midmid,L,R;
L=l;
R=r;
while(L+EPS<R){//由于L,R没有要求谁大谁小,故求的绝对值
Mid=(L+R)*0.5;
Midmid=(Mid+R)*0.5;
if(f(Mid)<=f(Midmid))
R=Midmid;
else
L=Mid;
}
return(L+R)*0.5;
}

intmain(){
inti;
doublel,r,nx;
while(cin>>n&&n){
l=200008;
r=-200008;
for(i=1;i<=n;i++){
scanf("%lf%lf",&x[i],&y[i]);
l=min(l,x[i]);
r=max(r,x[i]);
}
nx=tri_search(l,r);
printf("%.9lf%.9lf\n",nx,f(nx));
}
return0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: