求一个数的约数个数和所有约数的和
欧拉函数:
int Euler(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;
}
拓展中国剩余定理:
// r[i] 表示余数 m[i]表示约数
int excrt(int r[], int m[], int n)
{
int M = m[0], R = r[0], x, y, d;
for (int i = 1; i < n; ++i)
{
exgcd(M, m[i], d, x, y);
if ((r[i] - R) % d) return -1;
x = (r[i] - R) / d * x % (m[i] / d);
R += x * M;
M = M / d * m[i];
R %= M;
}
return R > 0 ? R : R + M;
}
拓展bsgs模板
// 如果时限很小的话可以手写hash加速
int EX_BSGS(int a,int b,int p)
{
a %= p;b %= p;
if (p==1) return 0;
if (!a&&!b) return 1;
if (b==1) return -1;
if (!a)return -1;
int d,step=0,k=1;
while ((d=gcd(a,p))!=1)
{
if (b%d){return -1;}
step++;p/=d;b/=d;k=(ll)k*a/d%p;
if (b==k){return step;}
}
map<int,int> mp;
int m=ceil(sqrt(p)),t=b;mp.clear();
for (int i=0;i<=m;i++){mp[t]=i;t=(ll)t*a%p;}
int A=qpow(a,m,p);
t = (ll)k*A%p;
for (int i=1;i<=m;i++)
{
int ans=t;t=(ll)t*A%p;
if (mp.find(ans)!=mp.end())
{
ans=i*m-mp[ans]+step;
return ans;
}
}
return -1;
}
欧拉函数打表:
const int N = 5e6+3;
int pcnt,prime[800000],euler[N];
bool st[N];
void getEulers(int n)
{ //欧拉筛的扩展
euler[1] = 1;
pcnt = 0;
for (int i=2; i <= n; i++ ){
if ( !st[i] ){
prime[pcnt++] = i;
euler[i] = i-1;
}
for(int j=0; prime[j] <= n/i; j++ ){
st[ prime[j]*i ] = 1;
if ( i % prime[j] == 0 ) {
euler[ i*prime[j] ] = euler[i] * prime[j];
break;
}
euler[ i*prime[j] ] = euler[i] * ( prime[j]-1 );
}
}
}
莫比乌斯函数打表
const int N = 5e4+15;
int prime[700000],pcnt;
bool mark[N];
int mu[N];
void getMu(){
memset(mark,0,sizeof(mark));
mark[0] = mark[1] = 1;
mu[1] = 1;
pcnt = 0;
for(int i = 2; i < N ; i ++){
if(!mark[i]){
prime[pcnt++] = i;
mu[i] = -1;
}
for(int j = 0 ; i*prime[j] < N && j < pcnt ; j ++){
mark[i*prime[j]] = 1;
if(i%prime[j] == 0) break;
else mu[i*prime[j]] = -mu[i];
}
}
}
组合数
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int maxn = 1e5+10;
typedef long long LL;
const LL MOD = 998244353;
LL fac[maxn],inv[maxn];
LL POW(LL x,LL y){
LL res = 1LL;
while(y){
if(y&1LL) res = res*x%MOD;
x = x*x%MOD;
y>>=1LL;
}
return res;
}
void Init(){
fac[0] = inv[0] = 1LL;
for(int i=1;i<maxn;i++){
fac[i] = fac[i-1]*i%MOD;
inv[i] = POW(fac[i],MOD-2);
}
}
LL C(LL n,LL m){
return fac[n]*inv[n-m]%MOD*inv[m]%MOD;
}
int main(void){
Init();
for(LL i=1;i<=12;i++){
for(LL j=1;j<=i;j++){
printf("C(%lld,%lld) = %lld\n",i,j,C(i,j));
}
}
return 0;
}
ps:数大的时候 int全为long long
素数筛:
const int N = 1e7+15;
int prime[700000],pcnt;
bool mark[N];
// 如果变量名都相同的话,就不用传参了
//void getPrimes(int prime[],int N,int &pcnt)
void getPrimes()
{
memset(mark,0,sizeof(mark));
mark[0] = mark[1] = 1;
pcnt = 0;
for(int i = 2; i < N ; i ++)
{
if(!mark[i])
prime[pcnt++] = i;
for(int j = 0 ; i*prime[j] < N && j < pcnt ; j ++)
{
mark[i*prime[j]] = 1;
if(i%prime[j] == 0)
break;
}
}
}
小区间 筛 大区间:
int prime2[N];
bool flag[N];
int p2cnt;
// pcnt 和 prime都是 getPrime产生的
void getPrimes2(int L,int R)
{
if(L <= 1) L = 2;
memset(flag, false, sizeof flag);
for(int i=0; i< pcnt && prime[i]<R; i++){
for(int j=(L+0ll+prime[i]-1)/prime[i]*prime[i]; j<=R; j+=prime[i]){
if(j!=prime[i]) flag[j-L]=true;
}
}
p2cnt=0;
for(int i=0;i<=R-L;i++){
if(!flag[i]) prime2[p2cnt++]=L+i;
}
}
快速乘:
ll qmul(ll a, ll b, ll mod) {
ll res = 0;
while(b) {
if(b & 1) res = (res + a) % mod;
a = (a + a) % mod;
b >>= 1;
}
return res;
}
快速幂:
// 带快速乘的快速幂
ll qpow(ll m,ll k,ll mod)
{
ll res=1%mod,t=m%mod;
while(k)
{
if(k&1)res=qmul(res,t,mod);
t=qmul(t,t,mod);
k>>=1;
}
return res;
}
// 大数 int换成long long
int qpow(int m, int k, int mod)
{
int res=1%mod,t=m%mod;
while(k)
{
if(k&1)res=res*t%mod;
t=t*t%mod;
k>>=1;
}
return res;
}
大素数判定
bool Millar(int p){
if(p==1)return 0;
int t=p-1,c=0;
while(t%2==0)t/=2,c++;
for(int i=0;i<5;i++){
int rd=rand()%p+rand(); //随机一个底数
int a=qpow(rd,t,p),last=a;
for(int j=1;j<=c;j++){
last=1LL*a*a%p;
if(last==1&&a!=1&&a!=p-1)return 0;
a=last;
}
if(a!=1)return 0;
}
return 1;
}
求模逆:
int inv(int x,int mod)
{
return qpow(x,mod-2,mod)%mod;
}
逆元打表:
long long re[N],inv[N],fac[N];
void getInv(int n){
re[0] = inv[1] = fac[0] = 1;
for(int i = 1;i <= n;++i) fac[i] = fac[i-1] * i % mod;
for(int i = 2;i <= n;++i) inv[i] = (mod-mod/i)*inv[mod%i] % mod;
for(int i = 1;i <= n;++i) re[i] = re[i-1] * inv[i] % mod;
}
long long c(int a,int b){
if(a < 0) return 0;
return fac[a]*re[b]%mod*re[a-b]%mod;
}
求GCD/LCM:
// 朴素版
int gcd(int a,int b)
{
return b==0 ? a : gcd(b,a%b);
}
// 加速版
int qgcd(int a, int b)
{
if(a == 0) return b;
if(b == 0) return a;
if(!(a & 1) && !(b & 1)) // a % 2 == 0 && b % 2 == 0;
return qgcd(a >> 1, b >> 1) << 1;
else if(!(b & 1))
return qgcd(a, b >> 1);
else if(!(a & 1))
return qgcd(a >> 1, b);
else
return qgcd(abs(a - b), min(a, b));
}
int lcm(int a,int b)
{
return a/gcd(a,b)*b; // 先除再乘 防爆操作
}
拓展欧几里得:
void exgcd(int a,int b,int &d,int &x,int &y)
{
if(!b) d=a, x=1, y=0;
else{
exgcd(b,a%b,d,y,x);
y-=x*(a/b);
}
}
求反素数:
typedef long long LL;
int ps[] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29};
int n; int sum = 0, minx;
//u:质因子序号, last:质因子指数, p:约数之积, s:约数个数
void dfs(int u, int last, int p, int s)
{
if (s > sum || s == sum && p < minx){ //更新反素数
sum = s;
minx = p;
}
for (int i = 1; i <= last; i ++ ) {
if ( (LL)p*ps[u] > n ) break;
p *= ps[u];
dfs( u+1, i, p, s*(i+1) );
}
}
int main()
{
cin >> n;
dfs(0, 30, 1, 1);
cout << minx << endl;
return 0;
}
矩阵运算:
const int MAXN=15;
int sz = 2;
struct Mat{
int dt[MAXN][MAXN];
Mat(int tp=0){ // 初始化 单位阵 tp = 1
for(int i=1;i <= sz;i++){
for(int j=1;j <= sz;j++){
if(i==j) dt[i][j]=tp;
else dt[i-1][j-1]=0;
}
}
}
void read(int n,int m){
for(int i = 1 ; i <= n ; i ++)
for(int j = 1; j <= m ; j ++)
{
cin>>dt[i][j];
scanf("%lld",&dt[i-1][j-1]);
}
}
Mat operator+(const Mat& a){
Mat res;
for(int i=1;i<=sz;i++){
for(int j=1;j<=sz;j++){
res.dt[i-1][j-1]=(dt[i-1][j-1]+a.dt[i-1][j-1])%MOD;
}
}
return res;
}
Mat operator-(const Mat& a){
Mat res;
for(int i=1;i<=sz;i++){
for(int j=1;j<=sz;j++){
res.dt[i-1][j-1]=(dt[i-1][j-1]-a.dt[i-1][j-1])%MOD;
}
}
return res;
}
Mat operator*(const Mat& a){
Mat res;
for(int i=1;i<=sz;i++){
for(int j=1;j<=sz;j++){
int sum=0;
for(int k=1;k<=sz;k++){
sum=(sum+dt[i-1][k-1]*a.dt[k-1][j-1])%MOD;
}
res.dt[i-1][j-1]=sum;
}
}
return res;
}
};
// 矩阵快速幂
Mat pow_mat(Mat ans, Mat x, ll n) {
while (n) {
if (n&1)
ans = x * ans;
x = x * x;
n >>= 1;
}
return ans;
}
整除分块:
int d = 0;
int res = 0;
for(int i = 1 ; i <= n ; i = d+1 ){
d = n/(n/i);
res += (d-i+1)*(n/i);
}