2017 暑假艾教集訓 day4

 題庫: 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)。





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章