/**********/ #include<iostream> #include<cstdio> #include<cmath> #include<algorithm> #include<cstring> #include<string> #include<cstdlib> #include<vector> #include<stack> #include<map> using namespace std; typedef long long ll; /***********GCD**********************/ ll gcd(ll a,ll b) { if(b==0) return a; return gcd(b,a%b); } /*************快速乘***************/ ll mult_mod(ll a,ll b,ll mod) { a%=mod; b%=mod; ll res=0; while(b) { if(b&1) { res+=a; res%=mod; } a<<=1; if(a>=mod) a%=mod; b>>=1; } return res; } /*************快速幂**************/ ll pow_mod(ll x,ll n,ll mod) { if(n==1) return x%mod; x%=mod; ll t=x,res=1; while(n) { if(n&1) res=mult_mod(res,t,mod); t=mult_mod(t,t,mod); n>>=1; } return res; } /*****更快的*****快速幂***************/ ll pow_mod(ll x,ll n,ll mod) { ll res=1; ll tmp=x%mod; while(n) { if(n&1) { res*=t; res%=mod; } n>>=1; t*=t; t%=mod; } return res; } /************扩展欧几里德****************/ void extend_gcd(ll a,ll b,ll &x,ll &y) { ll d; //d=gcd(a,b) if(b==0) { x=1,y=0; d=a; } else { d=extend_gcd(b,a%b,y,x); ll xx=x,yy=y; x=yy; y=xx-(a/b)*yy; } } /************素数筛法******************/ ll l,u,prime[N]; int tot; int vis[N],ans[10000005]; void isPrime() { tot=0; memset(vis,0,sizeof(vis)); memset(prime,0,sizeof(prime)); for(ll i=2;i<N;i++) { if(!vis[i]) { prime[tot++]=i; for(ll j=i*i;j<N;j+=i) vis[j]=1; } } } /******更快的*素数筛选*******************/ const int MAXN=10000; int prime[MAXN+1]; void isPrime() { memset(prime,0,sizeof(prime)); //素数存储从下标1开始,prime[0]记录素数个数 for(int i=2;i<=MAXN;i++) { if(!prime[i]) prime[++prime[0]]=i; for(int j=1;j<=prime[0]&&prime[j]<=MAXN/i;j++) { prime[prime[j]*i]=1; if(i%prime[j]==0) break; } } } /*********素数判定Miller_Rabin***********/ bool test(ll a,ll n) //Miller_Rabin算法的核心 { ll x=n-1,t=0,res,last; while((x&1)==0) { x>>=1; t++; } last=pow_mod(a,x,n); for(int i=0;i<t;i++) { res=pow_mod(last,2,n); if(res==1&&last!=1&&last!=n-1) return true; last=res; } if(res!=1) return true; return false; } bool millier_rabin(ll n) { if(n==2) return true; if(n==1||(n&1)==0) return false; for(int i=0;i<times;i++) { ll a=rand()%(n-1)+1; if(test(a,n)) return false; } return true; } /*******质因数分解********************/ ll factor[100][2]; int cnt; //分解质因数:A=(p1^a1)*(p2^a2)*...*(pn^an) //factor[i][0]=pi,factor[i][1]=ai; void getFactor(ll x) { cnt=0; ll t=x; for(int i=0;prime[i]<=t/prime[i];i++) { factor[cnt][1]=0; while(t%prime[i]==0) { factor[cnt][0]=prime[i]; while(t%prime[i]==0) { factor[cnt][1]++; t/=prime[i]; } cnt++; } } if(t!=1) { factor[cnt][0]=t; factor[cnt][1]=1; cnt++; } } /*********大数因数分解Pollard_rho*************/ ll pollard_rho(ll x,ll c) { ll x0,y,i=1,k=2; x0=rand()%x; y=x0; while(1) { i++; x0=(mult_mod(x0,x0,x)+c)%x; ll d=gcd(y-x0,x); if(d>1&&d<x) return d; if(y==x0) break; if(i==k) { y=x0; k+=k; } } return x; } void find_fac(ll n,int c) { if(n==1) return; if(millier_rabin(n)) { factor[tot++]=n; return; } ll p=n; while(p>=n) p=pollard_rho(p,c--); find_fac(p,c); find_fac(n/p,c); } /**********正约数和(二分求法)**************/ //将A进行因式分解可得:A = p1^a1 * p2^a2 * p3^a3 * pn^an //A^B=p1^(a1*B)*p2^(a2*B)*...*pn^(an*B); //A^B的所有约数之和sum=[1+p1+p1^2+...+p1^(a1*B)]*[1+p2+p2^2+...+p2^(a2*B)]*[1+pn+pn^2+...+pn^(an*B)]. //等比数列1+pi+pi^2+pi^3+...+pi^n可以由二分求得(即将需要求解的因式分成部分来求解) //若n为奇数,一共有偶数项,则 //1+p+p^2+p^3+........+p^n=(1+p+p^2+....+p^(n/2))*(1+p^(n/2+1)); //若n为偶数,一共有奇数项,则 //1+p+p^2+p^3+........+p^n=(1+p+p^2+....+p^(n/2-1))*(1+p^(n/2+1))+p^n/2; ll sum(ll p,ll n) { if(p==0) return 0; if(n==0) return 1; if(n&1) return ((1+pow_mod(p,n/2+1))%MOD*sum(p,n/2)%MOD)%MOD; else return ((1+pow_mod(p,n/2+1))%MOD*sum(p,n/2-1)+pow_mod(p,n/2)%MOD)%MOD; } /**********欧拉函数**********************/ int Euler(int n) { int res=n; for(int i=2;i*i<=n;i++) { while(n%i==0) { n/=i; res-=(res/i); while(n%i==0) n/=i; } } if(n>1) res-=(res/n); return res; } /******素数筛法+欧拉打表**********/ ll e[N+5],p[N+5]; bool vis[N+5]; void init() { memset(e,0,sizeof(e)); memset(p,0,sizeof(p)); memset(vis,false,sizeof(vis)); ll i,j; p[0]=1;//记录素数总个数 p[1]=2; for(i=3;i<N;i+=2) { if(!vis[i]) { p[++p[0]]=i; for(j=i*i;j<N;j+=i) vis[j]=true; } } e[1]=1; for(i=1;i<=p[0];i++) e[p[i]]=p[i]-1; //为什么要-1? for(i=2;i<N;i++) { if(!e[i]) { for(j=1;j<=p[0];j++) { if(i%p[j]==0) { if(i/p[j]%p[j]) e[i]=e[i/p[j]]*e[p[j]]; else e[i]=e[i/p[j]]*p[j]; break; } } } } } /*************欧拉打表*更快版***************/ #define N 1000000 int e[N+5]; void init() { int i,j; memset(e,0,sizeof(e)); for(i=2;i<=N;i++) { if(!e[i]) { for(j=i;j<=N;j+=i) { if(!e[j]) e[j]=j; e[j]=e[j]/i*(i-1); } } } } /**********容斥原理*二进制解法**************/ vector<int> v; ll solve(int l,int r,int n) //[l,r]内与n互素的数字个数 { v.clear(); //筛选素数 for(int i=2;i*i<=n;i++) { if(n%i==0) { v.push_back(i); while(n%i==0) n/=i; } } if(n>1) v.push_back(n); //容斥原理的二进制解法 int len=v.size(); ll res=0; for(int i=1;i<(1<<len);i++) { int cnt=0; ll val=1; for(int j=0;j<len;j++) { if(i&(1<<j)) { cnt++; val*=v[j]; } } if(cnt&1) //若为奇数项进行加法,偶数项进行减法 res+=r/val-(l-1)/val; else res-=r/val-(l-1)/val; } return r-l+1-res; }