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 1047和NYOJ 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; }