一些比较经典的题目

            

 

1、点P(x,y)绕点o(x0,y0)逆时针旋转a角度后的坐标为P'(x1,y1):

      x1=(x-x0)*cosa-(y-y0)*sina+x0;  y1=(x-x0)*sina+(y-y0)*cosa+y0

2、最大子矩阵和最大子段和模板,例题:NYOJ 1047NYOJ 14,下面以NYOJ 104代码为例,我觉得也要注意一下讨论区的那组数据,不是输出0,而是-2。

  1. <span style="font-family: Verdana;">#include<iostream>  
  2. #include<cstring>  
  3. #include<cstdio>  
  4. using namespace std;  
  5. const int MAX=110;  
  6. #define CLR(arr,val) memset(arr,val,sizeof(arr))   
  7. int num,n,m,map[MAX][MAX];  
  8. int Maxsum(int a[])//最大子段和模板  
  9. {   int sum=0,max=a[0];  
  10.     for(int i=0;i<m;i++)  
  11.     {   if(sum>0) sum+=a[i];  
  12.         else sum=a[i];  
  13.         if(sum>max) max=sum;  
  14.     }  
  15.     return max;  
  16. }  
  17. int Matrix()//最大子矩阵和模板   
  18. {   int max=map[0][0],temp[MAX];  
  19.     for(int i=0;i<n;i++)  
  20.     {   CLR(temp,0);  
  21.         for(int j=i;j<n;j++)  
  22.         {   for(int k=0;k<m;k++)  
  23.                 temp[k]+=map[j][k];       
  24.             int sum=Maxsum(temp);  
  25.             if(sum>max) max=sum;  
  26.         }   
  27.     }          
  28.     return max;  
  29. }  
  30. int main()  
  31. {   scanf("%d",&num);  
  32.     while(num--)  
  33.     {   scanf("%d%d",&n,&m);  
  34.         for(int i=0;i<n;i++)  
  35.             for(int j=0;j<m;j++)  
  36.                 scanf("%d",&map[i][j]);  
  37.         cout<<Matrix()<<endl;  
  38.     }  
  39.     return 0;  
  40. }</span>  
<span style="font-family:Verdana;">#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int MAX=110;
#define CLR(arr,val) memset(arr,val,sizeof(arr)) 
int num,n,m,map[MAX][MAX];
int Maxsum(int a[])//最大子段和模板
{   int sum=0,max=a[0];
    for(int i=0;i<m;i++)
    {   if(sum>0) sum+=a[i];
        else sum=a[i];
        if(sum>max) max=sum;
    }
    return max;
}
int Matrix()//最大子矩阵和模板 
{   int max=map[0][0],temp[MAX];
    for(int i=0;i<n;i++)
    {   CLR(temp,0);
        for(int j=i;j<n;j++)
        {   for(int k=0;k<m;k++)
                temp[k]+=map[j][k];     
            int sum=Maxsum(temp);
            if(sum>max) max=sum;
        } 
    }        
    return max;
}
int main()
{   scanf("%d",&num);
    while(num--)
    {   scanf("%d%d",&n,&m);
        for(int i=0;i<n;i++)
            for(int j=0;j<m;j++)
                scanf("%d",&map[i][j]);
        cout<<Matrix()<<endl;
    }
    return 0;
}</span>

3、筛选法求素数,例题:NYOJ 26(孪生素数),数据比较大,直接存储范围内的所有素数,再遍历即可。

  1. <span style="font-family: Verdana;">#include<iostream>  
  2. #include<cstring>  
  3. #include<cstdio>  
  4. using namespace std;  
  5. const int MAX=1000010;  
  6. #define CLR(arr,val) memset(arr,val,sizeof(arr))  
  7. int n,m,sum=0,num,visit[MAX],prime[MAX];  
  8. void Prime()//筛选法求素数模板   
  9. {   for(int i=2;i<MAX/2;i++)  
  10.     {   if(!visit[i])  
  11.             for(int j=i<<1;j<MAX;j+=i)  
  12.                 visit[j]=1;    
  13.     }    
  14.     for(int i=2;i<MAX;i++)  
  15.         if(!visit[i]) prime[sum++]=i;  
  16. }  
  17. int main()  
  18. {   CLR(prime,0);  
  19.     CLR(visit,0);  
  20.     Prime();  
  21.     scanf("%d",&m);  
  22.     while(m--)  
  23.     {   scanf("%d",&n);  
  24.         num=0;  
  25.         for(int i=1;prime[i]<=n;i++)  
  26.             if(prime[i]-prime[i-1]==1||prime[i]-prime[i-1]==2) num++;  
  27.         printf("%d\n",num);      
  28.     }  
  29.     return 0;  
  30. }</span>  
<span style="font-family:Verdana;">#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int MAX=1000010;
#define CLR(arr,val) memset(arr,val,sizeof(arr))
int n,m,sum=0,num,visit[MAX],prime[MAX];
void Prime()//筛选法求素数模板 
{   for(int i=2;i<MAX/2;i++)
    {   if(!visit[i])
            for(int j=i<<1;j<MAX;j+=i)
                visit[j]=1;  
    }  
    for(int i=2;i<MAX;i++)
        if(!visit[i]) prime[sum++]=i;
}
int main()
{   CLR(prime,0);
    CLR(visit,0);
    Prime();
    scanf("%d",&m);
    while(m--)
    {   scanf("%d",&n);
        num=0;
        for(int i=1;prime[i]<=n;i++)
            if(prime[i]-prime[i-1]==1||prime[i]-prime[i-1]==2) num++;
        printf("%d\n",num);    
    }
    return 0;
}</span>

3、蔡勒公式:求某一年是某一年的星期几?NYOJ 219

  1. <span style="font-family: Verdana;">#include<iostream>  
  2. #include<cstdio>   
  3. using namespace std;  
  4. int year,month,day;  
  5. int main()  
  6. {   while(scanf("%d%d%d",&year,&month,&day)!=EOF)//得使用c输入,不然会TLE   
  7.     {   if(month<=2) year-=1,month+=12;  
  8.         printf("%d\n",(day+1+2*month+3*(month+1)/5+year+year/4-year/100+year/400)%7);   
  9.     }  
  10.     return 0;  
  11. }   
  12. </span>  
<span style="font-family:Verdana;">#include<iostream>
#include<cstdio> 
using namespace std;
int year,month,day;
int main()
{   while(scanf("%d%d%d",&year,&month,&day)!=EOF)//得使用c输入,不然会TLE 
    {   if(month<=2) year-=1,month+=12;
        printf("%d\n",(day+1+2*month+3*(month+1)/5+year+year/4-year/100+year/400)%7); 
    }
    return 0;
} 
</span>

4、中国剩余定理

若某数x分别被d1、d2、…、dn除得的余数为r1、r2、…、rn,则可表示为下式:x=R1*r1+R2*r2+…+Rn*rn+RD
其中R1是d2、d3、…、dn的公倍数,而且被d1除,余数为1;...........

Rn是d1、d2、…、dn-1的公倍数,而且被dn除,余数为1;
D是d1、d2、…、dn的最小公倍数;
R是任意整数,且d1、d2、…、dn必须互质。

例题1:POJ 1006(生理周期),我看不懂题目,英语太差了,刚好网上又有这个题目的翻译,直接贴在代码中了~~完完全全的剩余定理,求满足求余条件的最小数。这个时候R为0,因为求最小的数。

  1. <span style="font-family: Verdana;">/**************************************************************************************************************** 
  2. Description 
  3. 人生来就有三个生理周期,分别为体力、感情和智力周期,它们的周期长度为23天、28天和33天。每一个周期中有一天是高峰。在 
  4. 高峰这天,人会在相应的方面表现出色。例如,智力周期的高峰,人会思维敏捷,精力容易高度集中。因为三个周期的周长不同, 
  5. 所以通常三个周期的高峰不会落在同一天。对于每个人,我们想知道何时三个高峰落在同一天。对于每个周期,我们会给出从当前 
  6. 年份的第一天开始,到出现高峰的天数(不一定是第一次高峰出现的时间)。你的任务是给定一个从当年第一天开始数的天数,输 
  7. 出从给定时间开始(不包括给定时间)下一次三个高峰落在同一天的时间(距给定时间的天数)。例如:给定时间为10,下次出现 
  8. 三个高峰同天的时间是12,则输出2(注意这里不是3)。 
  9. Input 
  10. 输入四个整数:p, e, i和d。 p, e, i分别表示体力、情感和智力高峰出现的时间(时间从当年的第一天开始计算)。d 是给定的 
  11. 时间,可能小于p, e, 或 i。所有给定时间是非负的并且小于365, 所求的时间小于21252。 
  12. 当p = e = i = d = -1时,输入数据结束。 
  13. Output 
  14. 从给定时间起,下一次三个高峰同天的时间(距离给定时间的天数)。采用以下格式: 
  15. Case 1: the next triple peak occurs in 1234 days. 
  16. 注意:即使结果是1天,也使用复数形式“days”。 
  17. ****************************************************************************************************************/  
  18. #include<iostream>  
  19. using namespace std;  
  20. int p,e,i,d,sum=1;  
  21. int Val(int a,int b,int c)  
  22. {   int num;  
  23.     for(num=b*c;;num+=b*c)  
  24.         if(num%a==1) break;  
  25.     return num;      
  26. }   
  27. int main()  
  28. {   while(cin>>p>>e>>i>>d)  
  29.     {   if(p==-1&&e==-1&&i==-1&&d==-1) break;  
  30.         int res=(p*Val(23,28,33)+e*Val(28,23,33)+i*Val(33,23,28))%21252-d;//这里的话可以直接算出来,可以节省时间。  
  31.         if(res<=0) res+=21252;  
  32.         cout<<"Case "<<sum++<<": the next triple peak occurs in "<<res<<" days."<<endl;          
  33.     }  
  34.     return 0;  
  35. } </span>  
<span style="font-family:Verdana;">/****************************************************************************************************************
Description
人生来就有三个生理周期,分别为体力、感情和智力周期,它们的周期长度为23天、28天和33天。每一个周期中有一天是高峰。在
高峰这天,人会在相应的方面表现出色。例如,智力周期的高峰,人会思维敏捷,精力容易高度集中。因为三个周期的周长不同,
所以通常三个周期的高峰不会落在同一天。对于每个人,我们想知道何时三个高峰落在同一天。对于每个周期,我们会给出从当前
年份的第一天开始,到出现高峰的天数(不一定是第一次高峰出现的时间)。你的任务是给定一个从当年第一天开始数的天数,输
出从给定时间开始(不包括给定时间)下一次三个高峰落在同一天的时间(距给定时间的天数)。例如:给定时间为10,下次出现
三个高峰同天的时间是12,则输出2(注意这里不是3)。
Input
输入四个整数:p, e, i和d。 p, e, i分别表示体力、情感和智力高峰出现的时间(时间从当年的第一天开始计算)。d 是给定的
时间,可能小于p, e, 或 i。所有给定时间是非负的并且小于365, 所求的时间小于21252。
当p = e = i = d = -1时,输入数据结束。
Output
从给定时间起,下一次三个高峰同天的时间(距离给定时间的天数)。采用以下格式:
Case 1: the next triple peak occurs in 1234 days.
注意:即使结果是1天,也使用复数形式“days”。
****************************************************************************************************************/
#include<iostream>
using namespace std;
int p,e,i,d,sum=1;
int Val(int a,int b,int c)
{   int num;
    for(num=b*c;;num+=b*c)
        if(num%a==1) break;
    return num;    
} 
int main()
{   while(cin>>p>>e>>i>>d)
    {   if(p==-1&&e==-1&&i==-1&&d==-1) break;
        int res=(p*Val(23,28,33)+e*Val(28,23,33)+i*Val(33,23,28))%21252-d;//这里的话可以直接算出来,可以节省时间。
        if(res<=0) res+=21252;
        cout<<"Case "<<sum++<<": the next triple peak occurs in "<<res<<" days."<<endl;        
    }
    return 0;
} </span>

5、完数:一个数恰好等于除它本身外的因子之和,1->99999999之间的完数只有:6,28,496,8126,33550336.
6、欧拉函数:对正整数n,欧拉函数是求少于或等于n的数中与n互质的数的数目,又称φ函数等。用φ(x)表示[1,n]中与n互质的数的个数。

用φ(x)的通式为:φ(x)=x(1-1/p1)(1-1/p2)(1-1/p3)(1-1/p4)…..(1-1/pn),其中p1, p2……pn为x的所有质因数,x是不为0的整数且φ(1)=1。

性质:若m,n互质,那么φ(mn)=φ(m)φ(n);

欧拉定理:设a和m都是整数(m>0),则有:aφ(m)≡1 (mod m)

例题1:NYOJ 333(mdd的烦恼),直接要你输出φ(n)的值,套用模板即可。

  1. <span style="font-family: Verdana;">#include<iostream>  
  2. using namespace std;  
  3. #define __int64 long long  
  4. __int64 n;  
  5. __int64 Euler()  
  6. {   __int64 value=n;  
  7.     for(int i=2;i*i<=n;i++)  
  8.         if(n%i==0)  
  9.         {   value-=value/i;  
  10.             while(n%i==0) n/=i;  
  11.         }  
  12.     if(n>1) value-=value/n;  
  13.     return value;      
  14. }  
  15. int main()  
  16. {   while(cin>>n)  
  17.         cout<<Euler()<<endl;  
  18.     return 0;  
  19. }  
  20. </span>  
<span style="font-family:Verdana;">#include<iostream>
using namespace std;
#define __int64 long long
__int64 n;
__int64 Euler()
{   __int64 value=n;
    for(int i=2;i*i<=n;i++)
        if(n%i==0)
        {   value-=value/i;
            while(n%i==0) n/=i;
        }
    if(n>1) value-=value/n;
    return value;    
}
int main()
{   while(cin>>n)
        cout<<Euler()<<endl;
    return 0;
}
</span>

例题2:POJ 3696(幸运数),意思是给你一个数L,构造一个幸运数,使得该数仅由数字8组成且是L的倍数中最小的那个正整数。

分析:设输入的数为L,且所求数的最短长度为k,那么幸运数为:Val=888......8(共有k个)=Lq(q为倍数),所以8*111.....1=Lq,由这个式子知,L中不可能含有5和16这两个因子。
设L=2tm;且t<=3,这个时候有23-t*111....1=mq,说明111....1是m的倍数,因为111.....1=(10k-1)/9,所以10k-1=9mq1 。这个时候有10k≡1(mod 9m) ,又由欧拉定理有10φ(9m)≡ 1 (mod 9m) ,又所以有:φ(9m)%k=0。 

 7、递推:nefu 27(数列异形),一个找规律的题,开始一看直接想到了矩阵,但是后来看来下数据范围1<=n<=1000000000,估计用矩阵也会超时,后来干脆打了个表,其实是以10为循环节的规律出现,具体打表程序如下:

  1. <span style="font-family: Verdana;">#include<iostream>  
  2. using namespace std;  
  3. int a[101];  
  4. int main()  
  5. {   a[1]=1,a[2]=1;  
  6.     for(int i=3;i<101;i++)  
  7.         a[i]=5*(a[i-1]+a[i-2])%11;  
  8.     for(int i=1;i<101;i++)   
  9.         cout<<a[i]<<endl;      
  10.     return 0;  
  11. }   
  12. </span>  
<span style="font-family:Verdana;">#include<iostream>
using namespace std;
int a[101];
int main()
{   a[1]=1,a[2]=1;
    for(int i=3;i<101;i++)
        a[i]=5*(a[i-1]+a[i-2])%11;
    for(int i=1;i<101;i++) 
        cout<<a[i]<<endl;    
    return 0;
} 
</span>

这个时候就简单啦,直接数组保存,出来啦~

  1. <span style="font-family: Verdana;">#include<iostream>  
  2. #include<cstdio>   
  3. using namespace std;  
  4. int a[10]={8,1,1,10,0,6,8,4,5,1};  
  5. int main()  
  6. {   int n;  
  7.     while(scanf("%d",&n)!=EOF)   
  8.         printf("%d\n",a[n%10]);     
  9.     return 0;  
  10. }   
  11. </span>  
<span style="font-family:Verdana;">#include<iostream>
#include<cstdio> 
using namespace std;
int a[10]={8,1,1,10,0,6,8,4,5,1};
int main()
{   int n;
    while(scanf("%d",&n)!=EOF) 
        printf("%d\n",a[n%10]);   
    return 0;
} 
</span>

8、统计数字出现的次数,例题:NYOJ 285(寻找克隆人)

  1. <span style="font-family: Verdana;">//第i行表示重复i次的DNA序列的个数.   
  2. #include<iostream>  
  3. #include<cstring>  
  4. #include<string>  
  5. #include<algorithm>  
  6. using namespace std;  
  7. const int MAX=10010;  
  8. #define CLR(arr,val) memset(arr,val,sizeof(arr))  
  9. string DNA[MAX];  
  10. int n,m,sum[MAX];   
  11. bool mysort(const string& s1,const string& s2)  
  12. {   if(s1.compare(s2)) return s1<s2;  
  13. }  
  14. int main()  
  15. {   while(cin>>n>>m,n+m)  
  16.     {   int temp=0;  
  17.         CLR(sum,0);  
  18.         for(int i=0;i<n;i++)  
  19.             cin>>DNA[i];  
  20.         sort(DNA,DNA+n,mysort);  
  21.         while(temp<n)  
  22.         {   int num=1;  
  23.             for(int i=temp+1;i<n;i++)  
  24.                 if(DNA[temp]==DNA[i])  
  25.                 {   temp=i;  
  26.                     num++;  
  27.                 }  
  28.             temp++;      
  29.             sum[num]++;  
  30.         }       
  31.         for(int i=1;i<=n;i++)  
  32.             cout<<sum[i]<<endl;  
  33.     }  
  34.     return 0;  
  35. }   
  36. </span>  
<span style="font-family:Verdana;">//第i行表示重复i次的DNA序列的个数. 
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
const int MAX=10010;
#define CLR(arr,val) memset(arr,val,sizeof(arr))
string DNA[MAX];
int n,m,sum[MAX]; 
bool mysort(const string& s1,const string& s2)
{   if(s1.compare(s2)) return s1<s2;
}
int main()
{   while(cin>>n>>m,n+m)
    {   int temp=0;
        CLR(sum,0);
        for(int i=0;i<n;i++)
            cin>>DNA[i];
        sort(DNA,DNA+n,mysort);
        while(temp<n)
        {   int num=1;
            for(int i=temp+1;i<n;i++)
                if(DNA[temp]==DNA[i])
                {   temp=i;
                    num++;
                }
            temp++;    
            sum[num]++;
        }     
        for(int i=1;i<=n;i++)
            cout<<sum[i]<<endl;
    }
    return 0;
} 
</span>

当然可以用map做,记得每次把map清空。

  1. <span style="font-family: Verdana;">#include<iostream>  
  2. #include<string>  
  3. #include<map>  
  4. #include<cstring>  
  5. using namespace std;  
  6. const int MAX=20010;  
  7. #define CLR(arr,val) memset(arr,val,sizeof(arr))  
  8. map<string,int> m;  
  9. int sum[MAX];  
  10. int main()  
  11. {   int n,num;  
  12.     string s;  
  13.     while(cin>>n>>num,n+num)  
  14.     {   CLR(sum,0);  
  15.         cin.get();  
  16.         for(int i=0;i<n;i++)  
  17.         {   cin>>s;  
  18.             m[s]++;  
  19.         }   
  20.         map<string,int>::iterator it;  
  21.         for(it=m.begin();it!=m.end();it++)  
  22.         {   sum[(*it).second]++;  
  23.             (*it).second=0; //清空map  
  24.         }  
  25.         for(int i=1;i<=n;i++)  
  26.             cout<<sum[i]<<endl;        
  27.     }       
  28.     return 0;  
  29. }</span>  
<span style="font-family:Verdana;">#include<iostream>
#include<string>
#include<map>
#include<cstring>
using namespace std;
const int MAX=20010;
#define CLR(arr,val) memset(arr,val,sizeof(arr))
map<string,int> m;
int sum[MAX];
int main()
{   int n,num;
    string s;
    while(cin>>n>>num,n+num)
    {   CLR(sum,0);
        cin.get();
        for(int i=0;i<n;i++)
        {   cin>>s;
            m[s]++;
        } 
        map<string,int>::iterator it;
        for(it=m.begin();it!=m.end();it++)
        {   sum[(*it).second]++;
            (*it).second=0; //清空map
        }
        for(int i=1;i<=n;i++)
            cout<<sum[i]<<endl;      
    }     
    return 0;
}</span>

9、求一个正整数的位数:log10(n)+1,可以利用这个方法来求n!的位数。
10、齐肯多夫定理:任何正整数可以表示为若干个不连续的Fibonacci数之和。
11、快速幂模:见下面的例题

描述

给你三个数X(1<=X<=10^100)、Y(1<=Y<=10^8)、Z(1<=Z<=10^4),你能计算出X^Y%Z的值吗?其中:X^Y表示X的Y次方。

输入

输入三个如上所描述的数X、Y、Z。多组输入。

输出

输出X^Y%Z的值。

样例输入

2 3 5
12345  2345  345 

样例输出

3
240

主要是X太大了,以字符串读入,然后对X%Z操作,利用(A+B)%C=(A%C+B%C)%C,还要利用快速幂模才能求出。

  1. #include<iostream>  
  2. #include<string>  
  3. using namespace std;  
  4. int Fun(int a,int b,int c)  
  5. {   int temp=a%c,d=1;  
  6.     while(b)  
  7.     {   if(b&1) d=(d*temp)%c;  
  8.         temp=(temp*temp)%c;  
  9.         b>>=1;   
  10.     }  
  11.     return d%c;  
  12. }  
  13. int Yus(string s,int c)  
  14. {   int yus=0;  
  15.     for(int i=0;i<s.length();i++)    
  16.         yus=((yus*10)%c+s[i]-'0')%c;  
  17.     return yus;      
  18. }  
  19. int main()  
  20. {   string s;   
  21.     int b,c;  
  22.     while(cin>>s>>b>>c)  
  23.     {   int a=Yus(s,c);  
  24.         cout<<Fun(a,b,c)<<endl;      
  25.     }  
  26.     return 0;  
  27. }  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值