费马小定理 :
也就是说ap1 %p=1
欧拉定理的推广----> 费马小定理 an-1 ≡1(mod n) 前提n是质数而且gcd(a,n)=1;
先看欧拉函数 phi(n) 即 φ(n)
欧拉函数 :φ(n) 表示小于等于n的与n互质的数的数量 如果n为质数 显然φ(n)=n-1;
标注:对于phi(1) 有的地方写的1 有的地方写的0 具体等于多少看题目的范围
int euler_phi(int n) {
int m = int(sqrt(n + 0.5));
int ans = n;
for (int i = 2; i <= m; i++)
if (n % i == 0) {
ans = ans / i * (i - 1);
while (n % i == 0) n /= i;
}
if (n > 1) ans = ans / n * (n - 1);
return ans;
}
欧拉定理的应用
前提 gcd(a,n) =1
aφ(n)≡1(mod n) <----> a*aφ(n)-1 ≡1(mod n); 由逆元表达式 ax≡1(mod n) 可知 aφ(n)-1 就是a在模n下的逆元
欧拉降幂公式 (a,n不要求互质)
如果要求 ab %n 其中b很大 (长度为1e6)
ab ≡ab%φ(n)+φ(n) (mod n)
即 ab % n=ab%φ(n) *aφ(n)%n
根据欧拉定理 aφ(n) ≡1(mod n) 即 aφ(n) %n=1 (有前提)
所以 ab =1 * ab%φ(n) 然后利用大数取模 +快速幂取模算就OK
例题 HDU 4704
注意前提QAQ 本题因为模数是质数
定义 Sk=(Σi=1i<=k xi )=N 的方案数 求Σi=1 i<=N (Si) %1e9+7
(QAQ本人语文不太好,若描述错误了请自行读题
对于数n 用隔板法 假设当前有n个 1
分成Sk 时 即k个数累加起来等于n 方案数C(n-1i-1) 全部累加起来方案数显然为 2n-1
那么答案就是 2n-1 %1e9+7 利用上述定理 组合拳
#include<stdlib.h>
#include<algorithm>
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<time.h>
#include <cstdio>
#include <iostream>
#include <vector>
#define ll long long
#define inf 0x3f3f3f3f
#define mods 1000000007
#define modd 998244353
#define PI acos(-1)
#define fi first
#define se second
#define lowbit(x) (x&(-x))
#define mp make_pair
#define pb push_back
#define si size()
#define E exp(1.0)
#define fixed cout.setf(ios::fixed)
#define fixeds(x) setprecision(x)
#define IOS ios::sync_with_stdio(false);cin.tie(0)
using namespace std;
ll gcd(ll a,ll b){if(a<0)a=-a;if(b<0)b=-b;return b==0?a:gcd(b,a%b);}
template<typename T>void read(T &res){bool flag=false;char ch;while(!isdigit(ch=getchar()))(ch=='-')&&(flag=true);
for(res=ch-48;isdigit(ch=getchar());res=(res<<1)+(res<<3)+ch - 48);flag&&(res=-res);}
ll lcm(ll a,ll b){return a*b/gcd(a,b);}
ll qp(ll a,ll b,ll mod){ll ans=1;if(b==0){return ans%mod;}while(b){if(b%2==1){b--;ans=ans*a%mod;}a=a*a%mod;b=b/2;}return ans%mod;}//快速幂%
ll qpn(ll a,ll b, ll p){ll ans = 1;a%=p;while(b){if(b&1){ans = (ans*a)%p;--b;}a =(a*a)%p;b >>= 1;}return ans%p;}//逆元 (分子*qp(分母,mod-2,mod))%mod;
ll pow_mod(ll x,ll n,ll mod){ll res=1;while(n){if(n&1)res=res*x%mod;x=x*x%mod;n>>=1;}return res;}
ll fact_pow(ll n,ll p){ll res=0;while(n){n/=p;res+=n;}return res;}
ll mult(ll a,ll b,ll p)
{
a%=p;
b%=p;
ll r=0,v=a;
while(b)
{
if(b&1)
{
r=(r+v)%p;
r=(r+p)%p;
}
v<<=1;
v=(v+p)%p;
b>>=1;
}
return r%p;
}
ll quick_pow(ll a,ll b,ll p){ll r=1,v=a%p;while(b){if(b&1)r=mult(r,v,p);v=mult(v,v,p);b>>=1;}return r;}
bool CH(ll a,ll n,ll x,ll t)
{ll r=quick_pow(a,x,n);ll z=r;for(ll i=1;i<=t;i++){r=mult(r,r,n);if(r==1&&z!=1&&z!=n-1)return true;z=r;}return r!=1;}
bool Miller_Rabin(ll n)
{if(n<2)return false;if(n==2)return true;if(!(n&1))return false;ll x=n-1,t=0;while(!(x&1)){x>>=1;t++;}
srand(time(NULL));ll o=8;for(ll i=0;i<o;i++){ll a=rand()%(n-1)+1;if(CH(a,n,x,t))return false;}return true;}
ll exgcd(ll a,ll b,ll &x,ll &y){
if (!b){
x=1,y=0;
return a;
}
ll ans=exgcd(b,a%b,y,x);
y-=(a/b)*x;
return ans;
}
ll INV(ll a,ll b){ll x,y;return exgcd(a,b,x,y),(x%b+b)%b;}
ll crt(ll x,ll p,ll mod){return INV(p/mod,mod)*(p/mod)*x;}
ll FAC(ll x,ll a,ll b)
{if(!x)return 1;ll ans=1;for(ll i=1;i<=b;i++)if(i%a)ans*=i,ans%=b;
ans=pow_mod(ans,x/b,b);for(ll i=1;i<=x%b;i++)if(i%a)ans*=i,ans%=b;return ans*FAC(x/a,a,b)%b;}
ll C(ll n,ll m,ll a,ll b)
{ll N=FAC(n,a,b),M=FAC(m,a,b),Z=FAC(n-m,a,b),sum=0,i;for(i=n;i;i=i/a)sum+=i/a;
for(i=m;i;i=i/a)sum-=i/a;for(i=n-m;i;i=i/a)sum-=i/a;return N*pow_mod(a,sum,b)%b*INV(M,b)%b*INV(Z,b)%b;}
ll exlucas(ll n,ll m,ll p)
{ll t=p,ans=0,i;for(i=2;i*i<=p;i++){ll k=1;while(t%i==0){k*=i,t/=i;}
ans+=crt(C(n,m,i,k),p,k),ans%=p;}if(t>1)ans+=crt(C(n,m,t,t),p,t),ans%=p;return ans % p;}
ll H(ll x,ll p) //错排
{
ll ans=0;
if(x==0)return 1;
x=x%(2*p);
if(x==0)x=2*p;
for(int i=2;i<=x;++i)
ans=(ans*i+(i%2==0?1:-1))%p;
return (ans+p)%p;
}
int euler_phi(int n) {
int m = int(sqrt(n + 0.5));
int ans = n;
for (int i = 2; i <= m; i++)
if (n % i == 0) {
ans = ans / i * (i - 1);
while (n % i == 0) n /= i;
}
if (n > 1) ans = ans / n * (n - 1);
return ans;
}
char s[1000009];
int main(){
ll MOD=mods-1;
while(scanf("%s",s+1)!=EOF){
ll n=strlen(s+1);
ll num=0;
for(int i=1;i<=n;i++){
num=num*10;
num=num+s[i]-'0';
num=num%MOD;
}
num=(num-1+MOD)%MOD;
printf("%lld\n",quick_pow(2,num,mods));
}
return 0;
}
欧拉降幂计算 模板题 FZUOJ 1759
计算AB %C 其中A C范围 1e9 B是一个范围为长度为1e6的数
与上面HDU不同的是,本题A与C可能不互质
根据拓展欧拉定理
对幂经行大数取模后 最值幂次加上φ© 就OK
综上 QAQ 对上午做个总结吧 欧拉降幂不需要底数与模数互质
ab %c
BZOJ 3884 拓展欧拉定理&欧拉降幂
对幂次递归就好了 直到φ(x) =1;
ll check(ll x){
if(x==1){
return 0;
}
ll MOD=euler_phi(x);
return quick_pow(2,check(MOD)+MOD,x);
}
char s[1000009];
int main(){
//ll ad;
ll MOD;
ll moddd;
ll t;
read(t);
while(t--){
read(moddd);
printf("%lld\n",check(moddd));
}
return 0;
}
反向求欧拉函数 不会做 - - 先留着 还有一个题是求【L R】区间内的
求欧拉函数前缀和
之前求单个欧拉函数值 复杂度sqrt(n) 显然不再适合这个题
预处理+O(1)查询
const int maxn=1e6+7;
int euler[maxn],prime[maxn],cnt;
void Get_Euler(int n)//求n以内所有数的欧拉函数值
{
memset(euler,0,sizeof(euler));
euler[1]=0;
cnt=0;
for(int i=2;i<=n;i++)
{
if(!euler[i])
{
euler[i]=i-1;
prime[cnt++]=i;
}
for(int j=0;j<cnt&&prime[j]*i<=n;j++)
{
if(i%prime[j])
euler[prime[j]*i]=euler[i]*(prime[j]-1);
else
{
euler[prime[j]*i]=euler[i]*prime[j];
break;
}
}
}
}
ll dp[maxn];
int main(){
Get_Euler(maxn);
for(int i=1;i<=maxn;i++){
dp[i]=dp[i-1]+euler[i];
}
int n;
while(scanf("%d",&n)!=EOF){
if(n==0){
break;
}
printf("%lld\n",dp[n]);
}
return 0;
}
求AB 的约数的和 A B范围 5e7 逆元的运用 以及快速乘
POJ 1845
ll mult(ll a, ll b, ll c)
{
ll ans = 0;
while(b)
{
if(b & 1)
ans = (ans+a)%c;
b>>=1;
a = (a+a)%c;
}
return ans;
}
ll pow_mod(ll x,ll n,ll mod)
{
ll res=1;
while(n)
{
if(n&1)
res=mult(res,x,mod);
x=mult(x,x,mod);
n>>=1;
}
return res;
}
const int manx=1e6+7;
//vector<ll>v[manx];
ll fac[manx/100];//质因子
ll num[manx/100]; //幂次
ll rnm=0;
ll cnt=0,ans=1;
ll p[manx];
bool prime[manx];
void isprime()
{
cnt= 0;
memset(prime, 0, sizeof(prime));
prime[1] = 1;
for(int i=2; i<manx; i++)
{
if(!prime[i])
{
p[++cnt] = i;
for(int j=i+i; j<manx; j+=i)
prime[j] = 1;
}
}
}
void check(ll x){ //质因子分解
rnm=0;
memset(num,0,sizeof(num));
for(int j=1;j<=cnt;j++){
if(p[j]*p[j]>x) break;
ll xx=0;
if(x%p[j]==0){
while(x%p[j]==0) x/=p[j],xx++;
rnm++;
fac[rnm]=p[j];
num[rnm]=xx;
}
}
if(x>1)
{
rnm++;
fac[rnm]=x;
num[rnm]=1;
}
}
int main(){
isprime();
ll a,B;
while(scanf("%lld%lld",&a,&B)!=EOF){
check(a); //素因子分解
ll ans=1,tmp;
for(int i=1;i<=rnm;i++){
ll MM=(fac[i]-1)*mods;
tmp=pow_mod(fac[i],num[i]*B+1,MM);
tmp--;
tmp=(tmp%MM+MM)%MM;
tmp/=(fac[i]-1);
ans=(ans*tmp)%mods;
}
ans=(ans%mods+mods)%mods;
printf("%lld\n",ans);
}
return 0;
}
唯一分解定理&GCD
给我们一个x =bp 求p的最大值
先欧拉筛打表素数 再对x质因子分解,注意x可能为负 - - 特判就好了
然后对所有的唯一分解后的幂次取gcd就好了
TLE死我了,有个变量一直没改过来
#include<stdlib.h>
#include<algorithm>
#include<stdio.h>
#include<string.h>
#include<time.h>
#include <cstdio>
#include <iostream>
#include <vector>
#define ll long long
#define inf 0x3f3f3f3f
#define mods 1000000007
#define modd 998244353
#define PI acos(-1)
#define fi first
#define se second
#define lowbit(x) (x&(-x))
#define mp make_pair
#define pb push_back
#define si size()
#define E exp(1.0)
#define fixed cout.setf(ios::fixed)
#define fixeds(x) setprecision(x)
#define IOS ios::sync_with_stdio(false);cin.tie(0)
using namespace std;
ll gcd(ll a,ll b){if(a<0)a=-a;if(b<0)b=-b;return b==0?a:gcd(b,a%b);}
template<typename T>void read(T &res){bool flag=false;char ch;while(!isdigit(ch=getchar()))(ch=='-')&&(flag=true);
for(res=ch-48;isdigit(ch=getchar());res=(res<<1)+(res<<3)+ch - 48);flag&&(res=-res);}
ll lcm(ll a,ll b){return a*b/gcd(a,b);}
ll qp(ll a,ll b,ll mod){ll ans=1;if(b==0){return ans%mod;}while(b){if(b%2==1){b--;ans=ans*a%mod;}a=a*a%mod;b=b/2;}return ans%mod;}//快速幂%
ll qpn(ll a,ll b, ll p){ll ans = 1;a%=p;while(b){if(b&1){ans = (ans*a)%p;--b;}a =(a*a)%p;b >>= 1;}return ans%p;}//逆元 (分子*qp(分母,mod-2,mod))%mod;
ll fact_pow(ll n,ll p){ll res=0;while(n){n/=p;res+=n;}return res;}
ll mult(ll a, ll b, ll c)
{
ll ans = 0;
while(b)
{
if(b & 1)
ans = (ans+a)%c;
b>>=1;
a = (a+a)%c;
}
return ans;
}
ll pow_mod(ll x,ll n,ll mod)
{
ll res=1;
while(n)
{
if(n&1)
res=mult(res,x,mod);
x=mult(x,x,mod);
n>>=1;
}
return res;
}
const int manx=1e6+7;
//vector<ll>v[manx];
ll fac[manx/100];//质因子
ll num[manx/100]; //幂次
ll rnm=0;
ll cnt=0,ans=0;
ll prime[manx];
bool minprime[manx];
void euler(int n) //欧拉筛
{
int i,j;
for(i=2; i<=n; i++)
{
if(!minprime[i])
prime[++cnt]=i,minprime[i]=1;
for(j=1; j<=cnt&&i*prime[j]<=n; j++)
{
minprime[i*prime[j]]=1;
if(i%prime[j]==0)
break;
}
}
}
void check(ll x){ //质因子分解
rnm=0;
memset(num,0,sizeof(num));
for(int j=1;j<=cnt;j++){
if(prime[j]*prime[j]>x) break;
ll xx=0;
if(x%prime[j]==0){
while(x%prime[j]==0) x/=prime[j],xx++;
rnm++;
fac[rnm]=prime[j];
num[rnm]=xx;
}
}
if(x>1)
{
rnm++;
fac[rnm]=x;
num[rnm]=1;
}
}
int main(){
euler(manx);
ll t;
ll n;
ll add=0;
read(t);
while(t--){
ans=0;
read(n);
ll flag=0;
if(n<0){
flag++;
n=-n;
}
check(n); //素因子分解
add++;
if(flag){
for(int i=1;i<=rnm;i++){
while(num[i]%2==0){
num[i]=num[i]/2;
}
}
}
//ll ans=fac[1];
for(int i=1;i<=rnm;i++){
ans=gcd(ans,num[i]);
//printf("%lld ",fac[i]);
}
printf("Case %lld: %lld\n",add,ans);
}
return 0;
}
今天就到这吧- - 改了好多BUG啊 TLE RE MEL 怀疑人生