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

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);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值