POJ 数论入门
题意:对于给定的a和p,判断$a^p\%p=a\%p$是否成立(p必须为素数)
思路:快速幂求$a^p$,由于数据量较小故$O(n^1/2)$判断素数即可
#include<cstdio>
#include<iostream>
using namespace std;
int powmod(int a, int n, int m){
if (n == 0) return 1;
int x = powmod(a, n/2, m);
long long ans = (long long)x * x % m;
if (n & 1) ans = ans * a % m;
return (int)ans;
}
int main(){
int p,a,i;
while((cin>>p>>a)&&(p!=0||a!=0)){
for( i=2;i*i<p;i=i+1){
if(p%i==0)
break;
}
if(i*i>=p){
cout<<"no"<<endl;
continue;
}
if(powmod(a,p,p)==a%p)
cout<<"yes"<<endl;
else cout<<"no"<<endl;
}
}
poj2478 Farey Sequence 欧拉函数
题目链接: http://poj.org/problem?id=2478
根据题意易知F(n)的个数为F(n-1)的个数加上小于n且与n互质的数个的数,即为n的欧拉函数。由于n的范围较大,故用筛选法打个n以内的欧拉函数表,再递推一下即可,注意可能会爆int $O(n*log n)$
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
#define Max 1000005
long long int euler[Max];
int main(){
euler[1]=1;
for(int i=2;i<Max;i++)
euler[i]=i;
for(int i=2;i<Max;i++)
if(euler[i]==i)
for(int j=i;j<Max;j+=i)
euler[j]=euler[j]/i*(i-1);
for(int i=3;i<=1000000;i++)
euler[i]=euler[i-1]+euler[i];
int n;
while((cin>>n)&&n!=0)
cout<<euler[n]<<endl;
}
题目链接: http://poj.org/problem?id=1995
题意:n组数据,每组数据给一个M和m组数:$a1...an,b1...bn$,求$(a_1^{b_1}+a_2^{b_2}+...+a_n^{b_n})\%n$
主要是快速幂(分治)求$a_i^{b_i}$,注意每求一次都对M 取一次模再求和避免溢出
#include<cstdio>
#include<algorithm>
#include<iostream>
using namespace std;
int powmod(int a, int n, int m){
if (n == 0) return 1;
int x = powmod(a, n/2, m);
long long ans = (long long)x * x % m;
if (n & 1) ans = ans * a % m;
return (int)ans;
}
int main(){
int n;
scanf("%d",&n);
while(n--){
int x[45005],y[45005];
int h,m,sum=0;
scanf("%d%d",&m,&h);
for(int i=0;i<h;i++){
scanf("%d%d",&x[i],&y[i]);
sum=((sum+powmod(x[i],y[i],m))%m);
}
printf("%d\n",sum);
}
}
题目链接:http://poj.org/problem?id=1664
母函数模板题:M个相同球放到N个相同的盒子中 $G(x) = (1+x+x^2+x^3+...x^k+...)(1+x+x^2+x^3+...x^k+...)$...(一共有 n 项)我们要求的就是x^m前面的系数
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<set>
#include<cmath>
using namespace std;
int n;
struct Z{
int val;
int num;
}z[10000];
int ans[100005],ans0[100005];
int main(){
int t;
cin>>t;
while(t--){
int m,n;
cin>>m>>n;
for(int i=0;i<=m;i++){
ans[i]=1;
ans0[i]=0;
}
for(int i=2;i<=n;i++){
for(int j=0;j<=m;j++){
for(int k=0;j+k<=m;k+=i)
ans0[j+k]+=ans[j];
}
for(int j=0;j<=m;j++){
ans[j]=ans0[j];
ans0[j]=0;
}
}
cout<<ans[m]<<endl;
}
}
题目链接: http://poj.org/problem?id=2084
题意:圆周上有标号为1,2,3...,2*n的共计2n个点,这2n个点配对可连成n条弦,且n条弦两两不相交,问共有多少连接方式
卡特兰数$C(n)=2(2n-1)*C(n-1)/n+1。。。。$(为啥呢==)
大数要处理,Java可以,但是不会啊,只有用笨办法了,用个数组存大数会处理进位就行
#include<cstdio>
#include<iostream>
using namespace std;
int num[105][105];
int main(){
num[0][1]=1;
num[1][1]=1;
int k=1;
for(int i=2;i<=100;i++){
int mul=4*i-2,j=1,x;
while(j<=k){
int z=mul*num[i-1][j];
x=j;
num[i][x]+=z%10;
num[i][x+1]+=z/10;
for(int x=j,y=1;y<=5;y++)
if(num[i][x]>=10){
num[i][x+1]+=(num[i][x]/10);
num[i][x]=num[i][x]%10;
x++;
}
j++;
}
for(int p=100;p>=1;p--)
if(num[i][p]!=0){
k=p;
break;
}
j=k;
while(j>=1){
num[i][j-1]+=(num[i][j]%(i+1)*10);
num[i][j]/=(i+1);
j--;
}
}
int n;
while((cin>>n)&&n!=-1){
for(int i=100;i>=1;i--){
if(num[n][i]!=0){
for(int j=i;j>=1;j--){
cout<<num[n][j];
}
cout<<endl;
break;
}
}
}
}
poj2356 Find a multiple 卡特兰数
题目链接: http://poj.org/problem?id=2356
题意:给你n个不大于15000的自然数,其中有些数可能相同,让你在其中选择一些数让他们的总和是n的倍数,若存在,输出选择数的个数和这些数,不存在则输出0
n<=10000;
设n个数分别为$a_1,a_2...a_n$,前缀和分别为$s_1,s_2...s_n$,让前缀和对n取模,则有n个取模后的数,这些数一定在0~n-1之间,由抽屉原理,这些数中一定有两个数相同,故答案即为这两个前缀之间的数,所以不存在输出0的情况
#include<cstdio>
#include<algorithm>
#include<iostream>
using namespace std;
int main(){
int n;
cin>>n;
int s,e;
int rem[10005]={0},z[10005]={0},a[10005];
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=1;i<=n;i++){
z[i]=z[i-1]+a[i];
z[i]=z[i]%n;
if(z[i]==0){
s=1;
e=i;
break;
}
else if(rem[z[i]]){
s=rem[z[i]]+1;
e=i;
break;
}
else rem[z[i]]=i;
}
printf("%d\n",e-s+1);
for(int i=s;i<=e;i++)
printf("%d\n",a[i]);
}
poj1006 Biorhythms 中国剩余定理
题目链接: http://poj.org/problem?id=1006
题意:人类从一开始有三个生物周期:体力、情绪和智力,周期分别为23、28和33天因而三个生物周期产生的高潮不同,已知每个生物周期上次高潮距离年初的天数d,以及从年初开始的一个天数(起始时间),问你下次生物周期高潮同时产生距离起始时间的天数
设下次高潮距离年初时间为x,m1=23,m2=28,m3=33 赏赐高潮产生的时间为b1,b2,b3
则由题意知:xi≡bi(mod mi)
由于m1,m2,m3互素,故用中国剩余定理即可
#include<cstdio>
#include<iostream>
using namespace std;
int x,y;
int Extended(int a,int b){
if(b==0){
x=1;
y=0;
return a;
}
int d=Extended(b,a%b);
int temp=x;
x=y;
y=temp-a/b*y;
return d;
}
int main(){
int cas=0;
int M=23*28*33;
int p,e,i,d;
while((cin>>p>>e>>i>>d)&&(p!=-1||e!=-1||i!=-1||d!=-1)){
int a[4]={p,e,i};
int m[4]={23,28,33};
int ans=0;
for(int i=0;i<3;i++){
int m0=M/m[i];
Extended(m0,m[i]);
ans=(ans+a[i]*m0*x)%M;
}
if(ans<=d)
ans+=M;
ans=ans-d;
cout<<"Case "<<++cas<<": the next triple peak occurs in "<<ans<<" days."<<endl;
}
}
poj1061 青蛙的约会
题目链接: http://poj.org/problem?id=1061
设t是跳的步数 由于每走L米就回原点,故可以建立一个同余方程(x+mt)≡(y+nt)%L =>(x+mt)-(y+nt)=kL => x-y=kL-(n-m)t,用欧几里得求最小的正整数t即可
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
long long x,y;
long long gcd(long long a,long long b){
if(b==0)
return a;
return gcd(b,a%b);
}
long long Extended(long long a,long long b){
if(b==0){
x=1;y=0;
return a;
}
long long d=Extended(b,a%b);
long long temp=x;
x=y;
y=temp-a/b*y;
return d;
}
int main(){
long long p,q,m,n,l,t1,t2;
cin>>p>>q>>m>>n>>l;
t1=t2=1e15;
if((p-q)%gcd(l,m-n)==0){
long long d=Extended(l,n-m);
long long t=l/d;
y=y*(p-q)/d;
t1=(y%t+t)%t;
}
if(t1==1e15)
cout<<"Impossible"<<endl;
else cout<<t1<<endl;
}
poj2891 Strange Way to Express Integers 同余方程组
题目链接: http://poj.org/problem?id=2891
题意:给你k对整数(ai,ri),已知对于每对整数,m%ai=ri,问你求m的最小值,不存在输出-1
#include<cstdio>
#include<iostream>
#include<algorithm>
typedef long long int ll;
using namespace std;
ll x,y;
ll Extended(ll a,ll b){
if(b==0){
x=1;y=0;
return a;
}
ll d=Extended(b,a%b);
ll temp=x;
x=y;
y=temp-a/b*y;
return d;
}
ll gcd(ll a,ll b){
if(b==0)
return a;
return gcd(b,a%b);
}
int main(){
int k;
while(cin>>k){
ll b1,b2,m1,m2;
cin>>m1>>b1;
bool f=1;
for(int i=1;i<k;i++){
cin>>m2>>b2;
if(f==1){
ll m=gcd(m1,m2);
if(((b2-b1)%m)!=0)
f=0;
else {
ll d=(b2-b1)/m;
Extended(m1,m2);
ll t=m2/m;
ll c=((x%t)*(d%t)%t+t)%t;
b1=b1+c*m1;
m1=m1*m2/m;
}
}
}
if(f==1){
cout<<b1<<endl;
}
else cout<<-1<<endl;
}
}

浙公网安备 33010602011771号