您的位置:首页 > 其它

sduacm16级寒假训练 素筛 快速幂 GCD

2017-02-03 15:20 141 查看
https://vjudge.net/contest/149323

Password:acmlab2016

A - A

【题意】

给你一个数,将它拆分成若干个连续素数的和,问有多少种方案

【思路】

给的数在2~10000,那么可以先处理出该范围的所有素数,去枚举连续素数的和,与给的数做判断.

【Code】

#include<cstdio>
const int Mx=10000;
int p[Mx+10];
bool f[Mx+10];
int main()
{
int n,ans,tot=0,sum;
for (int i=2;i<=Mx;i++)
if (!f[i])
{
tot++;
p[tot]=i;
int j=i*2;
while (j<=Mx)
{
f[j]=true;
j+=i;
}
}
while(scanf("%d",&n)&&n)
{
ans=0;
for (int i=1;i<=tot&&p[i]<=n;i++)
{
sum=0;
for (int j=i;j<=tot&&p[j]<=n;j++)
{
sum+=p[j];
if (sum==n) {
ans++;
break;
}
if (sum>n) break;
}
}
printf("%d\n",ans);
}
}


B - B

【题意】

给你[L,U]的区间,1<=L< U<=2,147,483,647,U-L<=1000000;

求出该区间内相邻最近和最远的两个素数,如果不存在两个素数,输出”There are no adjacent primes.”;

【思路】

数据范围那么大,枚举肯定不行的.

但是sqrt(2,147,483,647)≈46341,我们可以处理出[1,50000]范围内的素数,用这些素数去筛选区间内的数,

最后就是需要注意L=1的情况以及U=2,147,483,647的情况.

1是肯定不会被筛的,区间就换成[2,U].

U=2,147,483,647时,i++会爆掉..

【Code】

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int Mx=50000;
bool f[1000010];
int p[Mx+10];
int main()
{
int n,m,tot=0,x1,x2,y1,y2;
for (int i=2;i<=Mx;i++)
if (!f[i])
{
tot++;
p[tot]=i;
int j=i*2;
while (j<=Mx)
{
f[j]=true;
j+=i;
}
}
while (scanf("%d%d",&n,&m)!=EOF)
{
int nc=0,mx=0,mi=100000000,k;
memset(f,0,sizeof(f));
for (int i=1;i<=tot&&p[i]<=m;i++)
{
k=n/p[i];
if (n%p[i]!=0) k++;
if  (k==1) k++;
k=k*p[i];
while (k>=n&&k<=m)
{
f[k-n]=true;
k+=p[i];
}
}
for (int i=max(n,2);i<=m&&i-n<=m-n;i++)
if (!f[i-n])
{
if (!nc){
nc=i;
continue;
}
if (i-nc>mx)
{
mx=i-nc;
x1=nc;
x2=i;
}
if (i-nc<mi)
{
mi=i-nc;
y1=nc;
y2=i;
}
nc=i;
}
if (mi!=100000000) printf("%d,%d are closest, %d,%d are most distant.\n",y1,y2,x1,x2);
else printf("There are no adjacent primes.\n");
}
return 0;
}


C - C

【题意】

求(A1^B1+A2^B2+ … +AH^BH)mod M的值.

【思路】

快速幂.

【Code】

#include<cstdio>
int qpow(int a,int b,int c)
{
int tot=1;
while (b)
{
if (b&1) tot=((long long)tot*a)%c;
a=((long long)a*a)%c;
b=b>>1;
}
return tot;
}
int main()
{
int n,m,T,ans,a,b;
scanf("%d",&T);
while (T--)
{
scanf("%d",&m);
scanf("%d",&n);
ans=0;
for (int i=1;i<=n;i++)
{
scanf("%d %d",&a,&b);
ans=(ans+qpow(a,b,m))%m;
}
printf("%d\n",ans);
}
}


D - D

【题意】

p是素数,

那么p一定不是base-a pseudoprime;

p不是素数,

判断是否a^p与a关于模p同余,即判断a^p %p==a是否成立.

成立则p为base-a pseudoprime.

【思路】

注意p%i==0和!p%i,一开始因为这个纠结半天.

【Code】

#include<cstdio>
int quickpow(int a,int b,int c)
{
int tot=1;
while(b)
{
if (b&1)
tot=((long long)tot*a)%c;
a=((long long)a*a)%c;
b=b>>1;
}
return tot;
}
int main()
{
int a,p;
while (scanf("%d%d",&p,&a)&&a)
{
int s=1;
for (int i=2;i*i<=p;i++)
if (p%i==0){
s=0;
break;
}
if (s) printf("no\n");
else{
s=quickpow(a,p,p);
if (s==a) printf("yes\n");
else printf("no\n");
}
}
}


E - E

【题意】

一条首尾相接的数轴,两只青蛙,初始位置x、y,每次分别跳m、n求两只青蛙跳了多少次能相遇。

【思路】

构造方程 (x + m * s) - (y + n * s) = k * l(k = 0, 1, 2,…)

变形为 (n-m) * s + k * l = x - y。即转化为模板题,a * x + b * y = n,是否存在整数解。

然后用拓展欧几里得求出一组最小的可行解即可。

【Code】

#include<cstdio>
long long gcd(long long x,long long y)
{
if(y==0) return x;
return gcd(y,x%y);
}
void exgcd(long long a,long long b,long long &x,long long &y)
{
if(b==0)
{
x=1;
y=0;
return;
}
exgcd(b,a%b,x,y);
long long t= x;
x=y;
y=t-a/b*y;
return;
}
int main()
{
long long x,y,m,n,l;
while(~scanf("%lld %lld %lld %lld %lld",&x,&y,&m,&n,&l))
{
long long a=n-m,b=l,c=x-y,p,q;
long long d=gcd(a,b);
if(c%d)
{
puts("Impossible");
continue;
}
a/=d,b/=d,c/=d;
exgcd(a,b,p,q);
p*=c;
long long t=p%b;
while(t<0) t+=b;
printf("%lld\n",t);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  gcd poj