2020牛客暑假多校训练营 (第四场) B,F,H

B Basic Gcd Problem


打表找规律,通过观察我们可以发现,答案为 c^n的质因子个数,例如 12 可以质因子分解为 2,2,3,因此其答案为 c^3。

//打表
#include 
#include 
using namespace std;
int gcd(int x,int y)
{
    return y>0?gcd(y,x%y):x;
}
int fc(int x)
{
    if(x==1)
    return 1;
    int ma=0;
    for(int i=1;i<x;++i)
    {
        ma=max(ma,fc(gcd(x,i)));
    }
    return 3*ma;
}
int main()
{
    for(int i=1;i<=20;++i)
    printf("%d=%d\n",i,fc(i));
    return 0;
}
//AC代码
#include 
#include 
#include 
using namespace std;
const int maxn=1e6+5;
const long long mod=1e9+7;
long long su[maxn],cnt;
bool isprime[maxn];
int T;
long long n,c;
void prime()//素数筛
{
    cnt=1;
    memset(isprime,1,sizeof(isprime));//初始化认为所有数都是素数
    isprime[0]=isprime[1]=0;//0和1不是素数
    for(long long i=2;i<=maxn;i++)
    {
        if(isprime[i])
        su[cnt++]=i;//保存素数i
        for(long long j=1;j<cnt&&su[j]*i<=maxn;j++)
        {
            isprime[su[j]*i]=0;//筛掉小于等于i的素数和i的积构成的合数
        }
    }
}
long long getprimefactor(long long nn)
{
    int cas=0;
    for(int i=1;i<cnt&&su[i]*su[i]<=nn;++i)
    {
        while(nn%su[i]==0)
        {
            cas++;
            nn/=su[i];
        }
    }
    if(nn>1)
    cas++;
    return cas;
}
long long quickpow(long long a,long long b)
{
    long long s=1;
    while(b>0)
    {
        if(b&1)
        s=(s*a)%mod;
        b>>=1;
        a=(a*a)%mod;
    }
    return s;
}
int main()
{
    prime();
    scanf("%d",&T);
    while(T--)
    {
        scanf("%lld %lld",&n,&c);
        long long a=getprimefactor(n);
        printf("%lld\n",quickpow(c,a));
    }
    return 0;
}

F Finding the Order


这题只要把所有情况找出来,就可以发现,如果最长的边为 AD或者BC,那就是 AB//CD。如果最长的边为 AC或者BD,那就是 AB//DC。

#include 
#include 
using namespace std;
int T;
int a,b,c,d;
int main()
{
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d %d %d %d",&a,&b,&c,&d);
        int ma=max(max(a,b),max(c,d));
        if(ma==a||ma==d)
        puts("AB//DC");
        else
        puts("AB//CD");
    }
    return 0;
}

H Harder Gcd Problem


贪心+思维,先把所有素数*2>n的排除掉,在从后往前找每一个质因数,顺次匹配,遇到 2*p 先跳过,如果可以匹配的数量为奇数,最后的数与 2*p匹配。偶数则 2*p 不在这里匹配(可以留到前面去匹配)。

#include 
#include 
#include 
using namespace std;
const int maxn=2e5+5;
bool vis[maxn];//判断该数是否已经配对
bool isprime[maxn];
int su[maxn];
int T,n;
int ans[maxn];
int cnt,tot;
void prime()//素数筛
{
    cnt=1;
    memset(isprime,1,sizeof(isprime));//初始化认为所有数都是素数
    isprime[0]=isprime[1]=0;//0和1不是素数
    for(long long i=2;i<=maxn;i++)
    {
        if(isprime[i])
        su[cnt++]=i;//保存素数i
        for(long long j=1;j<cnt&&su[j]*i<=maxn;j++)
        {
            isprime[su[j]*i]=0;//筛掉小于等于i的素数和i的积构成的合数
        }
    }
}
void init()//初始化
{
    memset(vis,0,sizeof(vis));
    tot=0;
}
int main()
{
    prime();
    scanf("%d",&T);
    while(T--)
    {
        init();
        scanf("%d",&n);
        int r;
        for(int i=1;i<cnt&&su[i]<=n;++i)
        {
            if(su[i]*2>n)//如果一个素数*2>n,那么肯定不能使用
            vis[su[i]]=1;
            else
            {
                r=i;
            }
        }
        for(int i=r;i>=1;i--)
        {
            int s=0;//统计个数
            for(int j=1;j*su[i]<=n;++j)
            {
                if(j==2||vis[j*su[i]])
                continue;
                vis[j*su[i]]=1;
                ans[++tot]=j*su[i];
                s++;
            }
            if(s%2==1&&!vis[2*su[i]])
            {
                ans[++tot]=2*su[i];
                vis[2*su[i]]=1;
            }
        }
        printf("%d\n",tot/2);
        for(int i=1;i<=tot-1;i+=2)
        printf("%d %d\n",ans[i],ans[i+1]);
    }
    return 0;
}

你可能感兴趣的:(2020牛客暑假多校)