【模板】数学

数论

筛法

线性筛
//P3383 【模板】线性筛素数
#include <bits/stdc++.h>
using namespace std;
const int N=1e8+1,M=6e6+10;
int prime[M],cnt=0;
bool vis[N];

void get_prime( int n )
{
        memset( vis,0,sizeof(vis) ); cnt=0; 
        for ( int i=2; i<=n; i++ )
        {
                if ( !vis[i] ) prime[++cnt]=i; 
                for ( int j=1; j<=cnt && prime[j]*i<=N-1; j++ )
                {
                        vis[prime[j]*i]=1;
                        if ( i%prime[j]==0 ) break;
                }
        }
}

int main()
{
        int n,q; scanf( "%d%d",&n,&q );
        get_prime( n );
        while ( q-- )
        {
                int x; scanf( "%d",&x );
                printf( "%d\n",prime[x] );
        }

        return 0;
}
杜教筛
//Author: RingweEH
//P4213 【模板】杜教筛
const int N=5e5+10;
int pri[N],tot=0,n;
ll mu[N],phi[N];
bool is[N];

void Sieve()
{
    mu[1]=phi[1]=1; is[1]=1;
    for ( int i=2; i<=N-10; i++ )
    {
        if ( !is[i] ) { pri[++tot]=i,mu[i]=-1,phi[i]=i-1; }
        for ( int j=1; j<=tot && (i*pri[j]<=(N-10)); j++ )
        {
            is[i*pri[j]]=1;
            if ( i%pri[j]==0 ) { mu[i*pri[j]]=0,phi[i*pri[j]]=phi[i]*pri[j]; break; }
            mu[i*pri[j]]=-mu[i]; phi[i*pri[j]]=phi[i]*phi[pri[j]];
        }
    }
    for ( int i=2; i<=(N-10); i++ )
        mu[i]+=mu[i-1],phi[i]+=phi[i-1];
}

map<int,ll> mp_mu,mp_phi;

ll Sieve_Phi( int n )
{
    if ( n<=N-10 ) return phi[n];
    if ( mp_phi[n] ) return mp_phi[n];
    ll _res=0;
    for ( int l=2,r; l<=n; l=r+1 )
    {
        r=n/(n/l); _res+=(r-l+1)*Sieve_Phi(n/l);
        if ( r>=2147483647 ) break;
    }
    ll res=(ull)n*(n+1ll)/2ll-_res;
    mp_phi[n]=res; return res;
}

ll Sieve_Mu( int n )
{
    if ( n<=N-10 ) return mu[n];
    if ( mp_mu[n] ) return mp_mu[n];
    ll res=1;
    for ( int l=2,r; l<=n; l=r+1 )
    {
        r=n/(n/l); res-=(r-l+1)*Sieve_Mu(n/l);
        if ( r>=2147483647 ) break;
    }
    return mp_mu[n]=res;
}

int main()
{
    Sieve();
    int T=read();
    while ( T-- )
    {
        int n=read();
        printf("%lld %lld\n",Sieve_Phi(n),Sieve_Mu(n) );
    }
    return 0;
}

数论

BSGS
#include <bits/stdc++.h>
using namespace std;
int p,x,y;
map<int,int> M;

int power( int x,int y )
{
	int ans=1;
	for ( ; y; y>>=1,x=(1ll*x*x)%p )
		if ( y&1 ) ans=1ll*ans*x%p;
	return ans;
}

int main()
{
	scanf( "%d%d%d",&p,&x,&y );
	int m=sqrt(p)+1,s=y;
	for ( int i=0; i<m; i++ )
		M[s]=i,s=1ll*s*x%p;
	int pow=power( x,m ); s=1;
	for ( int i=1; i<=m; i++ )
	{
		s=1ll*s*pow%p;
		if ( M.count(s) ) 
		{
			printf( "%d\n",i*m-M[s] ); return 0;
		}
	}
	
	printf( "no solution" );
}
exBSGS
//Author: RingweEH
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <map>
#include <cmath>
#define ll long long
#define db double
using namespace std;

int Mod,x,y;
map<int,int> mp;

int power(int a,int b){int res=1;for(;b;b>>=1,a=1ll*a*a%Mod)if(b&1)res=1ll*res*a%Mod;return res;}
int gcd(int a,int b){ return (!b) ? a : gcd(b,a%b); }
void exBSGS( int x,int y )
{
	if ( y==1 ) { puts("0"); return ; }
	int d=gcd(x,Mod),k=1,t=0;
	while ( d^1 )
	{
		if ( y%d ) { puts("No Solution"); return; }
		t++; y/=d; Mod/=d; k=(x/d)*1ll*k%Mod;
		if ( y==k ) { printf("%d\n",t ); return; }
		d=gcd(x,Mod);
	}
	int s=y; mp.clear(); int m=sqrt(Mod)+1;
	for ( int i=0; i<m; i++ ) mp[s]=i,s=1ll*s*x%Mod;
	s=k; k=power(x,m);
	for ( int i=1; i<=m; i++ )
	{
		s=1ll*s*k%Mod;
		if ( mp[s] ) { printf("%d\n",i*m-mp[s]+t ); return; }
	}
	puts("No Solution");
}

int main()
{
//freopen( "exam.in","r",stdin );

	while ( scanf( "%d%d%d",&x,&Mod,&y ) && (x||Mod||y) ) 
		x%=Mod,y%=Mod,exBSGS(x,y);

	return 0;
}
exCRT
#include <cstdio>
#include <cmath>
#define ll long long
using namespace std;
int n;

ll exgcd( ll a, ll b, ll &x, ll &y )
{
        if ( b==0 ) { x=1,y=0; return a; }
        ll d=exgcd( b,a%b,y,x ); y-=a/b*x;
        return d;
}

ll inline mod( ll a,ll b )
{
        return ((a % b)+b)%b;
}

int main()
{
        scanf( "%d",&n );
        ll a1,m1; scanf( "%lld%lld",&a1,&m1 );
        for ( int i=1; i<n; i++ )
        {
                ll a2,m2,k1,k2; scanf( "%lld%lld",&a2,&m2 );
                ll d=exgcd( a1,-a2,k1,k2 );
                if ( (m2-m1)%d )
                { printf( "-1\n" ); return 0;  }
                k1=mod( k1*(m2-m1)/d,abs( a2/d ) );
                m1=k1*a1+m1; a1=abs( a1/d*a2 );
        }
        printf( "%lld\n",m1 );

        return 0;
}
exLucas
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N=11;
ll y,z,p,w[N];

ll power( ll a,ll b,ll p )
{
    ll res=1;
    for ( ; b; b>>=1,a=a*a%p )
        if ( b&1 ) res=res*a%p;
    return res;
}

ll exgcd( ll a,ll b,ll &x,ll &y )
{
    if ( !b ) { x=1; y=0; return a; }
    ll res=exgcd( b,a%b,x,y );
    ll t=x; x=y; y=t-a/b*y; return res;
}

ll fac( ll n,ll pi,ll pk )
{
    if ( !n ) return 1;
    ll res=1;
    for ( ll i=2; i<=pk; i++ )
        if ( i%pi ) (res*=i)%=pk;
    res=power( res,n/pk,pk );
    for ( ll i=2; i<=n%pk; i++ )
        if ( i%pi ) (res*=i)%=pk;
    return res*fac(n/pi,pi,pk)%pk;
}

ll inv( ll n,ll mod )
{
    ll x,y; exgcd( n,mod,x,y );
    return (x+=mod)>mod ? x-mod : x;
}

ll CRT( ll b,ll mod )
{
    return b*inv(p/mod,mod)%p*(p/mod)%p;
}

ll C( ll n,ll m,ll pi,ll pk )
{
    ll up=fac( n,pi,pk ),t1=fac( m,pi,pk ),t2=fac( n-m,pi,pk ),k=0;
    for ( ll i=n; i; i/=pi )
        k+=i/pi;
    for ( ll i=m; i; i/=pi )
        k-=i/pi;
    for ( ll i=n-m; i; i/=pi )
        k-=i/pi;
    return up*inv(t1,pk)%pk*inv(t2,pk)%pk*power(pi,k,pk)%pk;
}

ll exlucas( ll n,ll m )
{
    ll res=0,tmp=p,pk;
    int lim=sqrt(p)+5;
    for ( int i=2; i<=lim; i++ )
        if ( tmp%i==0 )
        {
            pk=1;
            while ( tmp%i==0 ) pk*=i,tmp/=i;
            res=(res+CRT(C(n,m,i,pk),pk))%p;
        }
    if ( tmp>1 ) res=(res+CRT(C(n,m,tmp,tmp),tmp))%p;
    return res;
}

int main()
{
    scanf( "%lld%lld%lld",&y,&z,&p );
    printf( "%lld",exlucas(y,z) );
}
二次剩余
//Author: RingweEH
//P5491 【模板】二次剩余
#include <cstdio>
#include <cstring>
#include <algorithm>
#define ll long long
#define db double
using namespace std;
int min( int a,int b ) { return a<b ? a : b; }
int max( int a,int b ) { return a>b ? a : b; }
void bmax( int &a,int b ) { a=(a>b) ? a : b; }
void bmin( int &a,int b ) { a=(a<b) ? a : b; }
int read()
{
    int x=0,w=1; char ch=getchar();
    while ( ch>'9' || ch<'0' ) { if ( ch=='-' ) w=-1; ch=getchar(); }
    while ( ch<='9' && ch>='0' ) x=x*10+ch-'0',ch=getchar();
    return x*w;
}

ll Mod,w,n;
struct Complex
{
	ll x,y;
	Complex( ll _x=0,ll _y=0 ) : x(_x),y(_y) {}
	Complex operator * ( Complex t ) { return Complex(x*t.x+y*t.y%Mod*w,x*t.y+y*t.x); }
	Complex operator % ( ll Mod ) { return Complex( (x%Mod+Mod)%Mod,(y%Mod+Mod)%Mod ); }
};

ll power( ll a,ll b,ll Mod ) { ll res=1; for ( ; b; b>>=1,a=a*a%Mod ) if ( b&1 ) res=res*a%Mod; return res; }
Complex power( Complex a,ll b,ll Mod ) { Complex res(1,0); for ( ; b; b>>=1,a=a*a%Mod ) if ( b&1 ) res=res*a%Mod; return res; }

ll Solve( ll n,ll P )
{
	n%=P;
	if ( power(n,(P-1)>>1,P)==P-1 ) return -1;	//判断无解
	ll a=0;
	while ( 1 )
	{
		a=rand()%P; w=(a*a+P-n)%P;
		if ( power(w,(P-1)>>1,P)==P-1 ) break;
	}
	return power( Complex(a,1),(P+1)>>1,P ).x%P;
}

int main()
{
	int T=read();
	while ( T-- ) 
	{
		n=read(); Mod=read();
		if ( n==0 ) { puts("0"); continue; }
		ll ans1=Solve(n,Mod),ans2=Mod-ans1;
		if ( ans1==-1 ) { puts("Hola!"); continue; }
		if ( ans1>ans2 ) swap( ans1,ans2 );
		printf( "%lld %lld\n",ans1,ans2 );
	}

	return 0;
}

线性代数

矩阵和行列式

高斯消元
//P3389 【模板】高斯消元法
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N=2010;
int n,cnt;
double a[N][N];

int main()
{
	scanf( "%d",&n );
	for ( int i=1; i<=n; i++ )
	 for ( int j=1; j<=n+1; j++ )
	 	scanf( "%lf",&a[i][j] );
	
	for ( int i=1; i<=n; i++ )
	{
		cnt=i;
		while ( a[cnt][i]==0 && cnt<=n ) cnt++;
		if ( cnt==n+1 ) { printf( "No Solution" ); return 0; }
		for ( int j=1; j<=n+1; j++ )
			swap( a[i][j],a[cnt][j] );
		double k=a[i][i];
		for ( int j=1; j<=n+1; j++ )
			a[i][j]/=k;
		for ( int j=1; j<=n; j++ )
			if ( i!=j )
			{
				double kt=a[j][i];
				for ( int m=1; m<=n+1; m++ )
					a[j][m]-=kt*a[i][m];
			}
	}
	
	for ( int i=1; i<=n; i++ )
		printf( "%.2lf\n",a[i][n+1] );
}
矩乘加速
//P1939 【模板】矩阵加速(数列)
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const ll mod=1e9+7;

struct matrix
{
        ll mt[5][5];
        matrix() { memset(mt,0,sizeof(mt)); }
        matrix  operator * ( matrix b )
        {
                matrix c;
                for ( int i=1; i<=3; i++ )
                 for ( int j=1; j<=3; j++ )
                  for ( int k=1; k<=3; k++ )
                        c.mt[i][j]=(c.mt[i][j]+(mt[i][k]*b.mt[k][j])%mod)%mod;
                return c;
        } 
}ans,base;

matrix power( ll b )
{
        matrix res=ans,a=base;
        for ( ; b; b>>=1,a=a*a )
                if ( b&1 ) res=res*a;
        return res;
}

int main()
{
        int T; scanf( "%d",&T );
        ans.mt[1][1]=1; ans.mt[1][2]=1; ans.mt[1][3]=1;
        base.mt[1][1]=1; base.mt[1][2]=1; base.mt[2][3]=1; base.mt[3][1]=1;
        while ( T-- )
        {
                ll n; scanf( "%lld",&n );
                if ( n<=3 ) { printf( "1\n"); continue; } 
                matrix res=power( n-3 );
                printf( "%lld\n",res.mt[1][1] );
        }
}

线性基

异或最大值
//Author:RingweEH
//P3812
const int N=55,MX=50;
int n;
ll a[N];

void Insert( ll x )
{
	for ( int i=MX; ~i; i-- )
		if ( x>>i&1 )
		{
			if ( !a[i] ) { a[i]=x; return; }
			x^=a[i];
		}
}

ll Query_mx( ll res=0 )
{
	for ( int i=MX; ~i; i-- )
		res=max( res,res^a[i] );
	return res;
}

int main()
{
	n=read();
	for ( int i=1; i<=n; i++ )
	{
		ll x=read(); Insert( x );
	}

	printf( "%lld\n",Query_mx() );

	return 0;
}
异或第 k 小
//Author:RingweEH
const int N=63,M=65;
int n,cnt;
ll a[M],b[M];
bool fl=0;

void Insert( ll x )
{
	for ( int i=N; ~i; i-- )
		if ( x>>i&1 )
		{
			if ( a[i] ) x^=a[i];
			else
			{
				a[i]=x;
				for ( int j=i-1; ~j; j-- )
					if ( a[j] && (a[i]>>j&1) ) a[i]^=a[j];
				for ( int j=N; j>i; j-- )
					if ( a[j]>>i&1 ) a[j]^=a[i];
				return;
			}
		}
	if ( x==0 ) fl=1;
}

int main()
{
	int T=read();
	for ( int cas=1; cas<=T; cas++ )
	{
		memset( a,0,sizeof(a) ); fl=0; cnt=0;

		n=read();
		for ( int i=1; i<=n; i++ )
		{
			ll x=read(); Insert( x );
		}

		for ( int i=0; i<=N; i++ )
			if ( a[i] ) b[cnt++]=a[i];
		int q=read(); printf( "Case #%d:\n",cas );
		while ( q-- )
		{
			ll k=read(),ans=0; k-=fl;
			if ( k>=(1ll<<cnt) ) { printf( "-1\n" ); continue; }
			for ( int i=0; i<cnt; i++ )
				if ( k>>i&1 ) ans^=b[i];
			printf( "%lld\n",ans );
		}
	}

	return 0;
}
实数线性基
//Author:RingweEH
//P3265 [JLOI2015]装备购买
const int N=510;
const db eps=1e-5;
struct Vector
{
	db a[N]; int val;
	db &operator [] ( const int &x ) { return a[x]; }
	bool operator < ( const Vector&tmp ) const { return val<tmp.val; }
}c[N];
int n,m,a[N];


int main()
{
	n=read(); m=read();
	for ( int i=1; i<=n; i++ )
		for ( int j=1; j<=m; j++ )
			scanf( "%lf\n",&c[i][j] );
	for ( int i=1; i<=n; i++ )
		c[i].val=read();

	sort( c+1,c+1+n ); int cnt=0; ll ans=0;
	for ( int i=1; i<=n; i++ )
		for ( int j=1; j<=m; j++ )
		{
			if ( fabs(c[i][j])<eps ) continue;
			if ( !a[j] ) { a[j]=i; cnt++; ans+=c[i].val; break; }
			db tmp=1.0*c[i][j]/c[a[j]][j];
			for ( int k=j; k<=m; k++ )
				c[i][k]-=tmp*c[a[j]][k];
		}

	printf( "%d %lld\n",cnt,ans );

	return 0;
}

组合数学

Prufer序列

Prufer序列模板
//Author: RingweEH
const int N=5e6+10;
int n,opt,deg[N],fa[N],prufer[N];
ll ans=0;

void TreeToPrufer()
{
	memset( deg,0,sizeof(deg) );
	for ( int i=1; i<n; i++ )
		fa[i]=read(),deg[fa[i]]++;
	for ( int i=1,pos=1; i<=n-2; i++ )
	{
		while ( deg[pos] ) pos++;		//找一个编号最小的叶节点
		prufer[i]=fa[pos];		//将其父亲加入序列
		for ( ; i<=n-2; )
		{
			deg[prufer[i]]--;
			if ( deg[prufer[i]] ) break;	//减完之后不是叶
			if ( prufer[i]>=pos ) break;	//是叶节点但是编号在后面
			prufer[i+1]=fa[prufer[i]]; i++; 	//新产生的点加入序列
		}
		pos++;
	}
	for ( int i=1; i<=n-2; i++ )
		ans=ans^(1ll*i*prufer[i]);
	printf( "%lld\n",ans );
}

void PruferToTree()
{
	memset( deg,0,sizeof(deg) );
	for ( int i=1; i<=n-2; i++ )
		prufer[i]=read(),deg[prufer[i]]++;
	prufer[n-1]=n;
	for ( int i=1,pos=1; i<n; i++ )
	{
		while ( deg[pos] ) pos++; 	//自增找一个叶节点
		fa[pos]=prufer[i];	//与当前序列首相连
		for ( ; i<n-1; )
		{
			deg[prufer[i]]--;
			if ( deg[prufer[i]] ) break;
			if ( prufer[i]>=pos ) break;
			fa[prufer[i]]=prufer[i+1]; i++;
		}
		pos++;
	}
	for ( int i=1; i<n; i++ )
		ans=ans^(1ll*i*fa[i]);
	printf( "%lld\n",ans );
}

int main()
{
	n=read(); opt=read();
	if ( opt==1 ) TreeToPrufer();
	else PruferToTree();

    return 0;
}
posted @ 2020-11-12 13:46  MontesquieuE  阅读(33)  评论(0编辑  收藏  举报