洛谷P3601 签到题
数论里面,对于 l 和 r 很大,r-l 范围又很小的时候,都用到了用一个数组x[ i ]表示 i+l 的值,也就是把 l~r 这个区间对应到 0~l-1 中了。
同时也预处理了可能对答案做出贡献的值(一般是预处理根号内的素数)。
与这道题很相似:
#include<bits/stdc++.h> using namespace std; #define N 1000005 #define ll long long #define ri register int int cnt=0,ans=0,pri[N],su[N],fl[N]; ll l,r; void suu(int n) { for(ri i=2;i<=n;++i){ if(!pri[i]) su[++cnt]=i; for(ri j=1;j<=cnt&&su[j]*i<=n;++j){ pri[su[j]*i]=1; if(i%su[j]==0) break; } } } int main() { scanf("%lld%lld",&l,&r); suu(sqrt(r)); for(int i=1;i<=cnt;++i){ for(ll j=l/su[i]*su[i];j<=r;j+=su[i]){ if(j>=l && j!=su[i]) fl[j-l]=1; } } for(ll i=l;i<=r;++i) if(fl[i-l]==0) ans++; printf("%d\n",ans); } /* 2 11 */
这道题也是一样,已知求单个欧拉的公式与其质因子有关,就预处理出 1~sqrt(r)的素数,然后枚举素数进行更新。
(注意题中要求的是与其不互质的数,用它本身减一下就行了)
#include<bits/stdc++.h> using namespace std; #define ll long long #define mod 666623333 #define N 1000005 ll l,r,su[N],phi[N],pri[N],tmp[N],cnt=0; void init() { ll x=sqrt(r); for(ll i=2;i<=x;++i){ if(!pri[i]) su[++cnt]=i; for(ll j=1;j<=cnt&&su[j]*i<=x;++j){ pri[su[j]*i]=1; if(i%su[j]==0) break; } } } void calc_phi() { for(ll i=0;i<=r-l;++i) tmp[i]=i+l,phi[i]=i+l; for(ll i=1;i<=cnt;++i){ ll ln=l/su[i]*su[i],rn=r/su[i]*su[i]; for(ll j=ln;j<=rn;j+=su[i]){//很像筛大素数的思路 预处理出可能做出贡献的值 跳着更新 把时间降到nlogn if(j<l) continue; phi[j-l]=phi[j-l]/su[i]*(su[i]-1);//利用公式计算 while(tmp[j-l]%su[i]==0) tmp[j-l]/=su[i]; } } for(ll i=0;i<=r-l;++i) if(tmp[i]>1) phi[i]=phi[i]/tmp[i]*(tmp[i]-1); } int main() { ll ans=0; scanf("%lld%lld",&l,&r); init(); calc_phi(); for(ll i=0;i<=r-l;++i) ans=(ans+i+l-phi[i])%mod; printf("%lld\n",ans); } /* 233 2333 */
P5091 【模板】欧拉定理
求a^m %mod 的时候,m过大,就可以由欧拉定理将m变成一个小于mod的数:
然后就是一个裸的板子了:
#include<bits/stdc++.h> using namespace std; #define ll long long ll phi,fl=0; ll read() { ll x=0; char ch=getchar(); while(ch<'0'||ch>'9'){ if(ch=='-') fl=-1; ch=getchar(); } while(ch<='9'&&ch>='0'){ x=(x*10+ch-'0'); if(x>=phi) fl=1,x%=phi; ch=getchar(); } return x; } ll quick_pow(ll a,ll k,ll mod) { ll ans=1; while(k){ if(k&1) ans=ans*a%mod; a=a*a%mod; k>>=1; } return ans; } ll calc_phi(ll x)//求单个欧拉 { ll ans=x; for(ll i=2;i<=sqrt(x);++i) if(x%i==0){ ans=ans/i*(i-1); while(x%i==0) x/=i; } if(x>1) ans=ans/x*(x-1); return ans; } int main() { ll a,m,b; scanf("%lld%lld",&a,&m); phi=calc_phi(m); b=read(); printf("%lld\n",quick_pow(a,b+fl*phi,m)); } /* 998244353 12345 98765472103312450233333333333 */