2017 暑假艾教集训 day4

来源:互联网 发布:期货分仓软件 编辑:程序博客网 时间:2024/06/08 08:35

 题库: https://cn.vjudge.net/contest/176263#overview

A:HDU 40704

做法:相当于将 n 任意组合, 可能的情况为 2^(n-1),因为n会很大,使用欧拉降幂公式


B:Given A,B,C, You should quickly calculate the result of A^B mod C. (1<=A,C<=1000000000,1<=B<=10^1000000).

做法:同上题一样算出C的欧拉数,做欧拉降幂


C:BZOJ 3884

做法:递归欧拉降幂。

#include <bits/stdc++.h>using namespace std;typedef long long ll;ll getoula(ll n){    if(n==1) return 0;    ll ans=n;    for(int i=2;i<=(int)sqrt(n+0.5);++i)    {        if(n%i==0)        {            ans = ans * (i-1) /i;            while(n%i==0) n/=i;        }    }    if(n>1) ans= ans * (n-1) /n;    return ans;}ll powermod(ll bit ,ll n, ll mod){    ll ans=1;    while(n)    {        if(n & 1) ans = (ans * bit) %mod;        bit = (bit * bit )%mod;        n>>=1;    }    return ans%mod;}ll f(ll p){    if(p==1) return 0;    int temp=getoula(p);    return powermod(2,f(temp)+temp,p);}int main(){    int T;    scanf("%d",&T);    while(T--)    {        ll p;        scanf("%lld",&p);        printf("%lld\n",f(p));    }    return 0;}

D POJ 2407

做法: 欧拉数水题

E POJ 2478

做法:筛发求欧拉数前缀和

F POJ 1845

做法:不难发现对于每个合适的sum等于其所有素数的等比数列和的积。

素数唯一定理,素数分解,等比数列递归求和,快速幂

#include <iostream>#include <cmath>#include <cstdio>#include <cstring>#include <algorithm>using namespace std;typedef long long ll;const ll mod = 9901;ll powermod(ll bit,ll n,ll mod){    bit=bit % mod;    ll ans=1;    while(n)    {        if(n & 1) ans = (ans * bit) %mod;        bit = (bit * bit) %mod;        n>>=1;    }    return ans;}ll sum(ll p ,ll n,ll mod){    if(p==0) return 0;    if(n==0) return 1;    if(n&1) return (  ( 1+powermod(p,n/2+1,mod) )%mod * sum(p,n/2,mod)%mod )%mod;    else return ( (1+powermod(p,n/2+1,mod)) %mod *sum(p,n/2-1,mod)+powermod(p,n/2,mod)%mod)%mod;}const int maxn=10000;bool book[maxn+10];int prim[maxn+10],pnum=0;void getprim(){    memset(book,0,sizeof(book));    pnum=0;    book[1]=book[0]=1;    for(int i=2;i<=maxn;++i)    {        if(!book[i])        {            prim[pnum++]=i;        }        for(int j=0;j<pnum && prim[j]<=maxn/i ;++j)        {            book[prim[j]*i]=1;            if(i % prim[j]==0) break;        }    }}ll fact[105][2];int fnum=0;int getfact(ll x){    fnum=0;    ll temp=x;    for(int i=0;prim[i]<=temp/prim[i];++i)    {        fact[fnum][1]=0;        if(temp%prim[i]==0)        {            fact[fnum][0]=prim[i];            while(temp % prim[i]==0)            {                fact[fnum][1]++;                temp /=prim[i];            }            fnum++;        }    }    if(temp!=1)    {        fact[fnum][0]=temp;        fact[fnum++][1]=1;    }    return fnum;}int main(){    ll a,b;    getprim();    while(scanf("%lld%lld",&a,&b)!=EOF)    {        getfact(a);        ll ans=1;        for(int i=0;i<fnum;++i)        {            ans = ( ans * sum( (ll)fact[i][0],(ll)b*fact[i][1],mod)%mod )%mod;        }        printf("%lld\n",ans);    }    return 0;}

G POJ 1811
做法:大数的素数检验,如果是合数的话算出最小质因
模板:Miller_rabin + Pollard_rho



K POJ 1284
做法:欧拉数的应用, 一个存在原根的数的原根数 等于 Phi(Phi(n));


M POJ 3090
做法:很容易发现,图关于y=x这条线对称。 且 每次增加的为与前项gcd(i,n)为1的个数
ans = 1 +2* Sigmn Phi[i]。



N  SPOJ 7001
题意:求GCD(X,Y,Z)=1 的种数 。
做法: 莫比乌斯函数反演,设 g(m)= GCD==x 的和 。 f(m) = GCD==kx 的和。 满足第二种莫比乌斯反演的形式
也不难发现 f(m)= [n/m]^3


 记着考虑 X,Y,Z有 一个0 两个 0的情况

#include <cmath>#include <cstdio>#include <cstring>#include <algorithm>#include <iostream>using namespace std;typedef long long ll;const int maxn=1000000;bool book [maxn+5];int prim[maxn+5];int cnt=0;int mu[maxn+5];void getprim(){    memset(book,1,sizeof(book));    cnt=0;    mu[1]=1;    for(int i=2;i<maxn ;++i)    {        if(book[i])        {            prim[cnt++] = i; mu[i]= -1;        }        for(int j=0;j<cnt && i*prim[j]<=maxn;++j)        {            book[i*prim[j]]=0;            if(i % prim[j]==0)            {                mu[i*prim[j]]=0;                break;            }            else            {                mu[i*prim[j]]= -mu[i];            }        }    }}int main(){    getprim();    int T;    scanf("%d",&T);    while(T--)    {        int n;        scanf("%d",&n);        ll ans=3;        for(int i=1;i<=n;++i) ans +=(ll) mu[i]*(n/i)*(n/i)*(n/i + 3);        printf("%I64d\n",ans);    }    return 0;}

HDU 1695

做法:求GCD(X,Y)==K 的种数 X属于(1,b) Y属于 (1,d)中 两边同除K。问题转换为 (1,b/K)(1,d/K)

求 GCD(x,y)==1;  和上一道题一样 直接莫比乌斯反演。

最后记着把 重复 的去掉

#include <bits/stdc++.h>using namespace std;typedef long long ll;const int maxn=100003;bool book [maxn+5];int p[maxn+5];int mu[maxn+5];int cnt=0;void getprime(){    memset(book,1,sizeof(book));    cnt=0;    mu[1]=1;    for(int i=2;i<maxn;++i)    {        if(book[i])        {            p[cnt++]=i; mu[i]= -1;        }        for(int j=0; j<cnt && i*p[j]<maxn;++j)        {            book[i*p[j]]=0;            if(i %p[j]==0)            {                mu[i *p[j]]= 0;                break;            }            else mu[i*p[j]] = -mu[i];        }    }}int main(){    getprime();    int T;    int kiss=0;    scanf("%d",&T);    while(T--)    {        int a,b,c,d,k;        scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);        if(k==0)        {            printf("Case %d: 0\n",++kiss);            continue;        }        int x=(b/k);        int y=(d/k);        ll ans1=0;        for(int i=1;i<=min(x,y);++i)        {            ans1 = ans1 +(ll) mu[i] * (x/i) * (y/i);        }        ll ans2=0;        for(int i=1;i<=min(x,y);++i)        {            ans2 =ans2 +(ll) mu[i] * (min(x,y)/i) *(min(x,y)/i);        }        printf("Case %d: %I64d\n",++kiss,ans1-ans2/2);    }    return 0;}

POJ 2417

做法:裸的离散对数 (BSGS)。