数学の入门到入土 第3天

费马小定理 :
在这里插入图片描述
也就是说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 怀疑人生

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值