数论题

来源:互联网 发布:淘宝购物券网站 编辑:程序博客网 时间:2024/04/28 02:32

zoj1823

升序方式打印一个数(longlong范围)的所有素数因子

Sample Input

90
1234567891
18991325453139
12745267386521023
-1


Sample Output

2
3
3
5

1234567891

3
3
13
179
271
1381
2423

30971
411522630413

#include<stdio.h>#include<string>#include<string.h>#include<iostream>using namespace std;int main(){    long long n,i;    while(cin>>n&&n>0)    {        i=2;        while(1)        {            if(n%i==0)//这样保证除的一定是素数            {                n/=i;                printf("%lld\n",i);            }            else i++;            if(i*i>n)            {                printf("%lld\n\n",n);                break;            }        }    }    return 0;}


ZOJ1037 求n*m维矩阵最短路  从起点出发经过一次且仅一次,最后回到起点

 

#include<iostream>#include<cstdio>#include<algorithm>using namespace std;/*     规律:偶数行或偶数列必定存在全部为1的路径把所有点连起来     否则m行n列中存在 m*n-1个1 和 一个 sqrt(2) 的路径连起所有点*/int main(){int t;int k=1;cin>>t;while(t--){    int  n,m;cin>>n>>m;printf("Scenario #%d:\n",k++);if(n%2==0||m%2==0)printf("%d.00\n",n*m);else printf("%.2lf\n",n*m-1+1.41);printf("\n");}return 0;}

ZOJ1049 求圆环半径 半圆的面积增量为50

r1*r1 - 0 = 100/pi

r2*r2 - r1*r1 = 100/pi

r3*r3 - r1*r1 = 100/pi

....

rn*rn - rn-1*rn-1=100/pi

故rn*rn=sqrt(100/pi)-sqrt(n) 循环一下即可

#include<cstdio>#include<cstdlib>#include<cstring>#include<cmath>#include<iostream>#define pi 3.1415926using namespace std;int main(){    int t;    cin>>t;    int k=1;    while(t--)    {        double x,y,s,p,tt;        cin>>x>>y;        s=sqrt(x*x+y*y);        int i=1;        p=0;        tt=sqrt(100/pi);        while(i)        {            p=tt*sqrt(i);            if(p>s){                printf("Property %d: This property will begin eroding in year %d.\n",k++,i);                break;            }            i++;        }    }    printf("END OF OUTPUT.\n");    return 0;}

或者 继续推导公式求解:

#include<cstdio>#include<cstdlib>#include<cstring>#include<cmath>#include<iostream>#define pi 3.1415926using namespace std;int main(){    int t;    cin>>t;    int k=1;    while(t--)    {        double x,y,s,p;        cin>>x>>y;        s=sqrt(x*x+y*y);        p=s/sqrt(100/pi);        p=(int)(p*p+0.5);        if(p==0)p=1;        printf("Property %d: This property will begin eroding in year %.0lf.\n",k++,p);    }    printf("END OF OUTPUT.\n");    return 0;}

ZOJ1041


求半圆扫到的最多点数

用叉积求是否在直径两边即可,当在直线上时,两边都要算

#include<iostream>#include<cstdio>#include<cstring>#include<cmath>using namespace std;double px,py;struct ss{    double x,y;} data[200];int mul(int i,int j){    double x1,y1,x2,y2;    x1=data[i].x-px;    y1=data[i].y-py;    x2=data[j].x-px;    y2=data[j].y-py;    double m=x1*y2-x2*y1;    if(fabs(m)<0.000001)return 0;    else if(m<0)return -1;    else return 1;}int main(){    double r,a,b,m;    while(cin>>px>>py>>r)    {        if(r<0)break;        int n,k=0,i,j;        cin>>n;        while(n--)        {            cin>>a>>b;            m=sqrt((px-a)*(px-a)+(py-b)*(py-b));            if(m<r||fabs(m-r)<0.0000001)            {                data[k].x=a;                data[k].y=b;                k++;            }        }        int ma=0;        for(i=0; i<k; i++)        {            int cnt1=0,cnt2=0;            int f;            for(j=0; j<k; j++)            {                f=mul(i,j);                if(f==-1)cnt1++;                else if(f==1)cnt2++;                else                {                    cnt1++;                    cnt2++;                }            }            if(ma<cnt1)ma=cnt1;            if(ma<cnt2)ma=cnt2;        }        printf("%d\n",ma);    }    return 0;}


计算时针与分针的夹角c(0<=c<=180)  h(0,23) m(0,59)

double getc(int h,int m){    if(h>=12)h=h-12;    h=h*60+m;    double a1=1.0*h/2;    double a2=1.0*m*6;    double temp=(a1>a2?a1-a2:a2-a1);    if(temp>=180)temp=360-temp;    return temp;}


Description

有一个屋里有n盏灯,灯的编号1,2,3,4。。。n-1,n.
每盏灯都对应一个开关,开关按一次可以将对应的灯的状态改变一次(亮着的熄灭,熄灭的点亮)
有个人很无聊,真的很无聊。。。
他按如下规律按灯的开关:
1,2,3,4,。。。(1及其倍数)
2,4,6,8,。。。(2及其倍数)
3,6,9,12 。。。(3及其倍数)
4  8  。 。 。。。(4及其倍数)
5  。 。 。 。。。(5及其倍数)
。 。 。 。 。。。(省略了很多行)
。 。 。 。 。。。(n及其倍数,也就是只有一个n)
过了很久很久,真的很久。。。他终于完成了,然后他要开始数有多少灯还亮着。

Input

每行一个n(1<=n<=109

Output

对于每个n输出最后亮着的灯的数量

Sample Input

10100

Sample Output

790

找规律...

假设所有灯初始状态为0,操作后变为  100100001000000...;
即 1+2+4+1+6+1+8+1+10+....

#include<cstdio>#include<cmath>using namespace std;int main(){    int n,k;    while(~scanf("%d",&n))    {        int k=sqrt(n);        while(k*k+2*k<n)k++;        k--;        int s=k+k*k;        n=n-(k*k+2*k);        if(n>=1)s+=n-1;        printf("%d\n",s);    }}

zoj2330

A^B == B^A?

Time Limit: 2 Seconds      Memory Limit: 65536 KB

Solve the equation in the name of this problem.

Input

There are several cases. Each of them has a single real number as the smaller one of a and b in the equation on a separate line. You may assume it's no smaller than 1.1. Proceed until the end of file.

Output

For each case, print the other number on a single line. Keep 5 digits after decimal point. If no such number exists, print -1.

Sample Input

2
10

Sample Output

4.00000
-1

要注意到一句话:输入的是ax中较小的那个,如果没有这句话的话就又是另一种做法了我们可以对方程两边同时取对数,从而得到:ln(a)/a=ln(x)/x移一下项得到f(x)=ln(a)/a-ln(x)/x,

求导可以计算得到1-ln(x)f(x)在(0e)上单调递减,在(e+无穷)上单调递增,x=e的时候f(x)有最小值。

 

而且f(x)x轴的两个交点就是所谓的可行解ab

那么我们很显然的可以得到ab分列于e的两边。

 

既然a是较小的那个,那么必然有a<e

故,当a已经大于了e就必然无解,这个时候输出-1

 

反之一定有解。

于是可以二分计算出答案。

注意到x>e的那个部分是单调递增的。


#include<stdio.h>#include<math.h>#define E exp(1.0f)//自然对数int main(){    double a;    while(scanf("%lf",&a)!=-1)    {        if(a>E)        {            printf("-1\n");        }        else        {            double l=E,r=44.0;            double mid=44.0;            bool flag=false;            while(l<=r)            {                mid=(l+r)/2.0;                //printf("mid=%.5lf\n",mid);                double temp1=log(a)/a;                double temp2=log(mid)/mid;                if(temp1<temp2)                {                    l=mid+0.000001;                }                else if(temp1>temp2) r=mid-0.000001;                else break;             }             printf("%.5lf\n",mid);        }    }    return 0;}


ZOJ3498找规律

题目分析 
 二分法,每次将不小于n/2个javabeans的盒子拿出n/2个javabeans, 
 然后规模就小了一半,一直进行此操作,知道所有盒子的球为0为止 

此题也就是求n的二进制的位数 

#include<cstdio>#include<iostream>using namespace std;int main(){    int t,n;    cin>>t;    while(t--)    {        cin>>n;        int s=0;        while(n)        {            n/=2;            s++;        }        cout<<s<<endl;    }    return 0;}


ZOJ1871 找规律

差值     排列

1              1

2            1 1

4            1 2 1

6         1 2 2 1

9        1 2 3 2 1

12     1 2 3 3 2 1

16    1 2 3 4 3 2 1

20    1 2 3 4 4 3 2 1

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<cmath>#define N 100using namespace std;int main(){    int n,m,len;    while(cin>>n>>m)    {        len=m-n;        int sum=0,step=0;        if(len==0){            printf("0\n");            continue;        }        for(int i=1;;i++)        {            sum+=i;            step++;            if(sum>=len)            {                printf("%d\n",step);                break;            }            sum+=i;            step++;            if(sum>=len)            {                printf("%d\n",step);                break;            }        }    }    return 0;}


Description

有一条长度为n的绳子,想要把这条绳子切成尽可能多的段,并且每段的长度必须为大于等于1的整数而且任意三段绳子都不能组成三角形。请问最多能切几段?

Input

测试文件的第一行有一个正整数T,代表一共有T组测试数据。
每组测试数据的第一行为一个正整数n(1<=n<=100000000)。

Output

对于每组测试数据,输出对应的答案。

Sample Input

3124

Sample Output

123
1 1 2 3 5 8 ... 要使切的边尽量小,并且任意三段能组成三角形

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>using namespace std;int main(){    int t,i;    int f[45];    f[0]=f[1]=1;    for(i=2;i<45;i++)f[i]=f[i-1]+f[i-2];    cin>>t;    while(t--)    {        int n;        cin>>n;        for(i=0;i<45;i++)        {            n-=f[i];            if(n<0)break;        }        printf("%d\n",i);             }    return 0;}

1466: Lucky Boy

Time Limit: 1 Sec  Memory Limit: 128 MB
Submit: 19  Solved: 6
[Submit][Status][Web Board]

Description

Recently, Lur have a good luck. He is also the cleverest boy in his school as he create the most popular computer game – Lucky Boy. The game is played by two players, a and b, in 2d planar .In the game Lucky Boy, there are n different points on plane, each time one can remove one or multiple co-line points from the plane. The one who can firstly remove more than two points from the plane wins. The one who removes the last point on the plane can also win the game. You may assume that two players are both clever enough that they can always make the best choice. The winner is called Lucky Boy. Given the n points, can you tell me who will be the Lucky Boy ? Note that player a will always the first one to remove points from the plane.

Input

The first line of each case is an integer n(0<n<=103), following n lines each contains two integers x and y(0<=x, y<=108), describing the coordinates of each point. Ended by EOF.

Output

Output “a is the lucky boy.” in a single line if a win the game, otherwise you should output  “b is the lucky boy.” in a single line.

Sample Input

30 01 12 230 01 12 3

Sample Output

a is the lucky boy.b is the lucky boy.

HINT

先判断是不是三点共线 让后博弈

#include<iostream>#include<cstdio>#include<algorithm>#include<vector>#include<string>#include<cmath>#include<map>#include<cstring>#define N 1010using namespace std;struct ss{    double x,y;}a[N],res[N*N];map<double,int>q;int main(){    int n,i,j,k;    while(~scanf("%d",&n))    {        q.clear();        for(i=0;i<n;i++)scanf("%d%d",&a[i].x,&a[i].y);        if(n<3){            printf("a is the lucky boy.\n");            continue;        }        int flag=0;        int num=0;        for(i=0;i<n;i++)        {            for(j=i+1;j<n;j++)            {                if(a[j].x-a[i].x==0)continue;                double tmp=(a[j].y-a[i].y)/(a[j].x-a[i].x);                res[num].x=i;                res[num].y=j;                int t=q[tmp];                if(q[tmp]&&(i==res[t].x||i==res[t].y||j==res[t].x||j==res[j].y)){                    flag=1;                    break;                }                else q[tmp]=num;                num++;            }            if(flag)break;        }        if(flag)printf("a is the lucky boy.\n");        else        {            if(n%3)printf("a is the lucky boy.\n");            else printf("b is the lucky boy.\n");        }    }    return 0;}

ZOJ

打表得出一部分Magic Number:

2
5
10
20
25
50
100
125
200
250
500

1000
1250
2000
2500
5000

10000
12500
20000
25000
50000

100000
125000
200000
250000
500000

1000000
1250000
2000000
2500000
5000000
10000000
12500000
20000000
25000000
50000000
100000000

Process returned 0 (0x0)   execution time : 12.393 s
Press any key to continue.

然后就好做了

#include<iostream>#include<cstdio>using namespace std;int main(){    long long a[100]={1,2,5,10,20,25,50};    long long p=1;    int i;    for(i=7;i<90;)    {        a[i++]=100*p;        a[i++]=125*p;        a[i++]=200*p;        a[i++]=250*p;        a[i++]=500*p;        p*=10;    }    //for(i=0;i<100;i++)printf("%d %lld\n",i+1,a[i]);   int  x,y;   while(~scanf("%d%d",&x,&y))   {       int s=0;       for(i=0;i<90;i++)       {           if(a[i]>y)break;           if(a[i]>=x&&a[i]<=y)s++;       }       printf("%d\n",s);   }    return 0;}

ZOJ1133

水题,本题讲的是判断一个数(排除素数)的各个数位之和是否等于将它分解成质数相乘形式时,各个数位之和

学会了怎样快速求质因子,

#include<cstdio>#include<cstring>#include<cmath>#include<iostream>#include<vector>using namespace std;vector<int>pri,fac;int get(int n){   int s=0;;   while(n)   {       s+=n%10;       n/=10;   }    return s;}int factor(int n){    fac.clear();    int i=0;    int num=n;    for(i=0;pri[i]<=n&&i<pri.size();i++)    {        while(n>=pri[i]&&n%pri[i]==0){            n/=pri[i];            fac.push_back(pri[i]);        }    }    if(n!=1)fac.push_back(n);   /* printf("fac: ");    for(i=0;i<fac.size();i++)printf("%d ",fac[i]);    printf("\n");    */    if(fac[0]==num)return -1;    else{        int s=0;        for(i=0;i<fac.size();i++)s+=get(fac[i]);        return s;    }}void inti(){    pri.clear();    int i,j;    for(i=2;i<10010;i++)//测试数据 sqrt(N)<10010    {        for(j=2;j<=sqrt(i);j++)if(i%j==0)break;        if(j>sqrt(i))pri.push_back(i);    }  //  for(i=0;i<pri.size();i++)printf("%d\n",pri[i]);}int main(){    int n,i;    inti();    while(~scanf("%d",&n)&&n)    {        while(n++)        {            int x=get(n);            int y=factor(n);          //  printf("** %d %d\n",x,y);           // getchar();            if(x==y)            {                printf("%d\n",n);                break;            }        }    }    return 0;}

ZOJ3716

题意:给你四个点,四个人在四个点上舞动丝带,各条丝带不能相遇,求四人最大的丝带总长度,即求最大的半径和。

#include<cstdio>#include<cstring>#include<cmath>#include<vector>#include<iostream>#include<algorithm>using namespace std;double x[5],y[5];double dis(double x1,double y1,double x2,double y2){    return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));//相乘结果超出int范围,所以数据类型都用double}int main(){    while(~scanf("%lf%lf",&x[0],&y[0]))    {        int i;        for(i=1;i<4;i++)scanf("%lf%lf",&x[i],&y[i]);        double d1=dis(x[0],y[0],x[1],y[1]);        double d2=dis(x[0],y[0],x[2],y[2]);        double d3=dis(x[0],y[0],x[3],y[3]);        double d4=dis(x[1],y[1],x[2],y[2]);        double d5=dis(x[1],y[1],x[3],y[3]);        double d6=dis(x[2],y[2],x[3],y[3]);        double ans=min(d1+d6,min(d2+d5,d3+d4));        printf("%.8lf\n",ans);    }    return 0;}

zoj3785

思路:

打表i的i次方%7后的值,就可以发现42一循环

然后用公式计算出结果

最后输出即可

4、AC代码:

[cpp] view plaincopy
  1. #include<stdio.h>  
  2. int s[45];  
  3. char str[7][10]={"Saturday","Sunday","Monday","Tuesday","Wednesday","Thursday","Friday"};  
  4. int main()  
  5. {  
  6.     s[0]=0;  
  7.     for(int i=1;i<=44;i++)  
  8.     {  
  9.         int flag=i%7;  
  10.         int ans=1;  
  11.         for(int j=1;j<=i;j++)  
  12.             ans=(ans*flag)%7;  
  13.         s[i]=ans;  
  14.     }  
  15.     for(int i=1;i<=44;i++)  
  16.         {s[i]+=s[i-1];}  
  17.     int t;  
  18.     while(scanf("%d",&t)!=EOF)  
  19.     while(t--)  
  20.     {  
  21.         int n;  
  22.         scanf("%d",&n);  
  23.         int ans=(n/42%7*(s[42]%7)%7+s[n%42]%7)%7;  
  24.          printf("%s\n",str[ans]);  
  25.     }  
  26. }  

通过打表发现周期是294,那么就简单了

[cpp] view plaincopy
  1. #include <stdio.h>  
  2. #include <string.h>  
  3. #include <algorithm>  
  4. using namespace std;  
  5.   
  6. char day[10][10] = {"Saturday","Sunday""Monday""Tuesday""Wednesday""Thursday""Friday"};  
  7. int s[300];  
  8.   
  9. int work(int n)  
  10. {  
  11.     int sum = 1,i;  
  12.     for(i = 1;i<=n;i++)  
  13.     {  
  14.         sum = sum*n;  
  15.         sum%=7;  
  16.     }  
  17.     return sum;  
  18. }  
  19.   
  20. int main()  
  21. {  
  22.     int t,n,i,j,len;  
  23.     s[0] = 0;  
  24.     for(i = 1;i<=294;i++)  
  25.     {  
  26.         s[i] = s[i-1]+work(i);  
  27.         s[i]%=7;  
  28.     }  
  29.     scanf("%d",&t);  
  30.     while(t--)  
  31.     {  
  32.         scanf("%d",&n);  
  33.         n%=294;  
  34.         printf("%s\n",day[s[n]]);  
  35.     }  
  36.   
  37.   
  38.     return 0;  
  39. }  


hdu4920 Matrix multiplication 模3矩阵乘法

hdu4920

Matrix multiplication

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Total Submission(s): 568    Accepted Submission(s): 225
Problem Description
Given two matrices A and B of size n×n, find the product of them.
bobo hates big integers. So you are only asked to find the result modulo 3.
 
Input
The input consists of several tests. For each tests:
The first line contains n (1≤n≤800). Each of the following n lines contain n integers -- the description of the matrix A. The j-th integer in the i-th line equals Aij. The next n lines describe the matrix B in similar format (0≤Aij,Bij≤109).
 
Output
For each tests:
Print n lines. Each of them contain n integers -- the matrix A×B in similar format.
 
Sample Input
1 0 1 2 0 1 2 3 4 5 6 7
 
Sample Output
0 0 1 2 1
 
Author
Xiaoxu Guo (ftiasch)
 
Source
2014 Multi-University Training Contest 5
 
Recommend
We have carefully selected several similar problems for you:  4919 4918 4917 4916 4914

2014多校5的最水的题,我没做出来,怕了。

题意:给出两个n*n的矩阵A和B,求A*B结果矩阵,元素都模3,n<=800。

题解:矩阵乘法加剪枝(?)。

800*800的矩阵,多组数据,直接算是会超时得飞起来的,只有考虑模3的特殊性。

读入后每个元素模3,得到的矩阵里全是0,1,2,随机数据的话有三分之一是零,所以我们的矩阵乘法要用k i j的循环嵌套顺序,第二层里面发现A[i][k]==0时就continue,直接少一维,也就是1/3概率少一维。这个是这题最关键的一步,没想到这步的话,其他再怎么优化也没用(我们试过了……)。

另外运算时可以使用cal[i][j][k]提前计算好((i*j)+k)%3,矩阵乘法的时候直接用这个结果。

 

------------------------------其他------------------------------------

顺便说个笑话:为什么Dijkstra没发明Floyd算法?因为他是ijk不是kij……

比赛的时候我们做这题优化得飞起来,读入输出优化,gets按字符串读一行来处理,输出用putchar,乘法、取余运算用上面说的那步省掉,输出不用'0'+C[i][j]而用数组存好ch[0]='0'这样输出,就差用fread一次读多行了……可是就是TLE,因为我们没想到最关键那步……

 

代码:

#include<cstdio>#include<cmath>#include<iostream>#include<cstring>#include<algorithm>#include<cmath>#include<map>#include<set>#include<stack>#include<queue>using namespace std;#define ll __int64#define usint unsigned int#define mz(array) memset(array, 0, sizeof(array))#define minf(array) memset(array, 0x3f, sizeof(array))#define REP(i,n) for(int i=0;i<(n);i++)#define FOR(i,x,n) for(int i=(x);i<=(n);i++)#define RD(x) scanf("%d",&x)#define RD2(x,y) scanf("%d%d",&x,&y)#define RD3(x,y,z) scanf("%d%d%d",&x,&y,&z)#define WN(x) printf("%d\n",x);#define RE  freopen("D.in","r",stdin)#define WE  freopen("1.out","w",stdout)int n;const int maxn=800;int A[maxn][maxn],B[maxn][maxn],C[maxn][maxn];int cal[3][3][3];int main() {    int i,j,k;    for(i=0; i<3; i++)        for(j=0; j<3; j++)            for(k=0; k<3; k++)                cal[i][j][k]=((i*j)+k)%3;    while(scanf("%d",&n)!=EOF) {        for(i=0; i<n; i++)            for(j=0; j<n; j++) {                scanf("%d",&A[i][j]);                A[i][j]%=3;            }        for(i=0; i<n; i++)            for(j=0; j<n; j++) {                scanf("%d",&B[i][j]);                B[i][j]%=3;            }        mz(C);        for(k=0; k<n; k++)            for(i=0; i<n; i++) {                if(A[i][k]==0)continue;///这个是关键!模3有三分之一是零,也就有三分之一概率去一维,碉!                for(j=0; j<n; j++) {                    ///re.a[i][j]=(re.a[i][j]+(A.a[i][k]*B.a[k][j]));                    C[i][j]=cal[A[i][k]][B[k][j]][C[i][j]];                }            }        for(i=0; i<n; i++) {            for(j=0; j<n-1; j++) {                putchar(C[i][j]+'0');                putchar(' ');            }            putchar(C[i][n-1]+'0');            puts("");        }    }    return 0;}





0 0
原创粉丝点击