2017 暑假艾教集训 day4

xiaoxiao2021-02-27  190

 题库: 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)。

转载请注明原文地址: https://www.6miu.com/read-13186.html

最新回复(0)