一些比较经典的题目和结论

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。

#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;
}

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

#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;
}

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

#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;
} 

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,因为求最小的数。

/****************************************************************************************************************
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;
} 

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)的值,套用模板即可。

#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;
}

例题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为循环节的规律出现,具体打表程序如下:

#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;
} 

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

#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;
} 

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

//第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;
} 

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

#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;
}

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,还要利用快速幂模才能求出。

#include<iostream>
#include<string>
using namespace std;
int Fun(int a,int b,int c)
{   int temp=a%c,d=1;
    while(b)
    {   if(b&1) d=(d*temp)%c;
        temp=(temp*temp)%c;
        b>>=1; 
    }
    return d%c;
}
int Yus(string s,int c)
{   int yus=0;
    for(int i=0;i<s.length();i++)  
        yus=((yus*10)%c+s[i]-'0')%c;
    return yus;    
}
int main()
{   string s; 
    int b,c;
    while(cin>>s>>b>>c)
    {   int a=Yus(s,c);
        cout<<Fun(a,b,c)<<endl;    
    }
    return 0;
} 


 

 

 


 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(敏捷,情感,ini,input,Matrix,output)