暂时性的模板

文章目录

      • KMP
      • 快速乘
        • 普通版
        • 快速版
      • 快速幂
      • 欧拉函数
      • 线性筛欧拉函数
      • 线性筛莫比乌斯函数
      • 逆元
      • RMQ_ST
      • Miller_Rabin
      • 线性基
        • 异或下的线性基
        • 实数下的线性基
      • BigInt
      • fft求高精度快速幂
      • 倍增
      • 约瑟夫问题
      • 中国剩余定理
      • 扩展中国剩余定理
      • 卢卡斯
      • 扩展卢卡斯
      • 指数循环
      • BSGS
      • 莫比乌斯反演
      • 积性函数
      • 迪利克雷卷积
      • 杜教筛
      • Min_25筛
      • 组合数
      • 最长公共子序列
      • 高斯消元
      • SG函数
      • 三分求极值
      • 轮廓线dp
      • 最长回文串
      • 数位dp
      • 最长上升子序列(LIS)
      • 容斥
        • 一个简单的排列问题
        • (0,1,2)序列问题
        • 方程整数解问题
      • 其他
        • 在[1,n]中与n互质的数的和
        • 勾三股四弦五
        • __int128_t的使用
        • 卡特兰数

KMP

int s[maxn], t[maxn], Next[maxn];//ss 大 tt小
string tt, ss;
int tlen, slen;
void getNext() {//自己跟自己比较,求的是 子串的最大前缀和最大后缀的长度
    int j, k;
    j = 0; k = -1; Next[0] = -1;
    while(j < tlen)//j是tt的从小到大的子串,第一个字符到第j个字符,k是对于每个子串的遍历
        if(k == -1 || tt[j] == tt[k])
            Next[++j] = ++k;
        else 
            k = Next[k];
}
int KMP_Index() {//查找第一次出现的位置
    int i = 0, j = 0;
    getNext();
    while(i < slen && j < tlen) {
        if(j == -1 || ss[i] == tt[j]) {
            i ++; j ++;
        }
        else //一旦失配,就移动到前面的前缀位置,重新匹配
            j = Next[j];
 
    }
    if(j == tlen)
        return i - tlen;
    return -1;
}
int KMP_Count() {//查找次数
    int ans = 0;
    int i, j = 0;
    
    if(slen == 1 && tlen == 1) {
        if(ss[0] == tt[0]) return 1;
        return 0;
    }
    getNext();
    for (i = 0; i < slen; i ++) {
        while(j > 0 && ss[i] != tt[j])
            j = Next[j];
        if(ss[i] == tt[j])
            j ++;
        if(j == tlen) {
            ans ++; j = Next[j];
        }
    }
    return ans;
}
int main(int argc, const char * argv[]) {
    cin >> ss >> tt;
    tlen = (int)tt.length();
    slen = (int)ss.length();
    printf("%d\n%d", KMP_Index(), KMP_Count());
    return 0;
}

快速乘

普通版

ll mul(ll a, ll b) {
    ll ans = 0;
    while(b) {
        if(b & 1) ans = (ans + a ) % p;
        b >>= 1;
        a = (a + a) % p;
    }
    return ans;
}

快速版

LL mul(LL a, LL b, LL P){
    LL L = a * (b >> 25LL) % P * (1LL << 25) % P;
    LL R = a * (b & ((1LL << 25) - 1)) % P;
    return (L + R) % P;
}

快速幂

ll p;
ll mul(ll a, ll b) {
    ll ans = 0;
    while(b) {
        if(b & 1) ans = (ans + a ) % p;
        b >>= 1;
        a = (a + a) % p;
    }
    return ans;
}
ll pow(ll a, ll b) {
    ll res = 1;
    ll base = a;
    while(b) {
        if(b & 1) res = mul(res, base) % p;
        base = mul(base, base) % p;
        b >>= 1;
    }
    return res;
}

欧拉函数

int oula(int n) { //O(n)
    int rea = n;
    for (int i = 2; i <= n; i ++) {
        if(n % i == 0) {
            rea = rea - rea/i;
            do{
                n /= i;
            }while(n % i == 0);
        }
    }
    return rea;
}
int oula_youhua(int n){//O(√n)
    int rea = n;
    for (int i = 2; i * i <= n; i ++) {
        if(n % i == 0) {
            rea = rea - rea / i;
            do{
                n /= i;
            }while(n % i == 0);
        }
    }
    if(n > 1)
        rea = rea - rea / n;
    return rea;
}
bool Isprime[50000];
int p[maxn];
void prim() {//素数打表
    memset(Isprime, 0, sizeof(Isprime));
    Isprime[0] = Isprime[1] = 1;
    int k = 0;
    for (int i = 2; i < 50000; i ++) {
        if(!Isprime[i])
            p[k++] = i;
        for (int j = 0; j < k && i * p[j] < 50000; j ++) {
            Isprime[i *p[j]] = 1;
            if(!(i % p[j]))
                break;
        }
    }
}
//筛法打表
int phi(int n){
    int rea = n;
    for (int i = 0; p[i] * p[i] <= n; i ++) {
        if(n % p[i] == 0) {
            rea = rea - rea / n;
            do{
                n /= p[i];
            }while(n % p[i] == 0);
        }
    }
    if(n > 1)
        rea = rea - rea / n;
    return rea;
}
 
void ditui() {//递推打表
    int i,j;
    for(i = 1; i < maxn; i++)
        p[i] = i;
    for(i = 2;i < maxn; i++){
        if(p[i] == i){
            for(j = i; j < maxn; j += i){
                p[j] = (p[j] / i) * (i-1);
            }
        }
    }
}

线性筛欧拉函数

void init() {
    phi[1] = 1;
    for(LL i = 2; i <= M; i ++) {
        if(!mark[i]) {
            prim[++tot] = i;
            phi[i] = i - 1;
        }
        for (LL j = 1; j <= tot; j ++) {
            if(i * prim[j] > M) break;
            mark[i * prim[j]] = 1;
            if(i % prim[j] == 0) {
                phi[i * prim[j]] = phi[i] * prim[j];
                break;
            }
            phi[i *prim[j]] = phi[i] * phi[prim[j]];
        }
    }
}

线性筛莫比乌斯函数

bool vis[Maxn];
int mu[Maxn], prim[Maxn];

void Mobius() {
    mu[1] = 1;
    int tot = 0;
    for (int i = 2; i <= Maxn; i ++) {
        if(!vis[i]) {
            prim[tot ++] = i;
            mu[i] = -1;
        }
        for (int j = 0; j < tot; j ++){
            if(i * prim[j] > Maxn) break;
            vis[i * prim[j]] = true;
            if(i % prim[j] == 0) {
                mu[i * prim[j]] = 0;
                break;
            }
            mu[i * prim[j]] = - mu[i];
        }
    }
}


逆元

int inv[N];
void invv(int n, int m) {//递推打表
    inv[1] = 1;
    for (int i = 2; i <= n; i ++)
        inv[i] = (ll)(m - m / i) * inv[m % i] % m;
}
 
ll Qpow(ll x, ll n){
    ll res=1;
    while(n>0){
        if(n&1)res=res*x%M;
        x=x*x%M;
        n>>=1;
    }
    return res;
}
void init() { // 递推打阶乘的的逆元
	fac[0] = 1;
	for (int i = 1; i <= maxn; i ++)
		fac[i] = (fac[i - 1] * i) % M;
	inv[maxn] = Qpow(fac[maxn], M - 2);
	
	for (int i = maxn - 1; i >= 0; i --) 
		inv[i] = (inv[i + 1] * (i + 1)) % M;
}

//扩展欧几里得求逆元
LL extend_gcd(LL a, LL b, LL &x, LL &y) {
	if(!b) {
		x = 1; y = 0;
		return a;
	}
	LL d = extend_gcd(b, a % b, x, y);
	LL t = x;
	x = y; y = t - (a / b) * y;
	return d;
}

LL getInv(LL a, LL b) {
	LL x, y;
	extend_gcd(a, b, x, y);
	x = (x % b + b) % b;
	return x;
}

RMQ_ST

int dp[maxn][30];
int main()
{
    int n;
    scanf("%d", &n);
    memset(dp, INF, sizeof(dp));
    for (int i = 1; i <= n; i ++)
        scanf("%d", &dp[i][0]);
    int base = 1;
    for (int i = 1; (base << 1) <= n; i ++) {
        for (int j = 1; j + base <= n; j ++) {
            dp[j][i] = min(dp[j][i - 1], dp[j + base][i - 1]);
        }
        base <<= 1;
    }
    int q;
    scanf("%d", &q);
    while(q --) {
        int L, R;
        scanf("%d %d", &L, &R);
        int p = log2(R - L + 1), k = 1 << p;
        int ans = min(dp[L][p], dp[R - k + 1][p]);
        printf("%d\n", ans);
    }
    return 0;
}

Miller_Rabin

#define random(a, b) (((double)rand()/RAND_MAX)*(b-a)+a)

LL Quick_Mul(LL a, LL b, LL n) {
    LL res = 0;
    while(b) {
        if(b & 1) res = (res + a) % n;
         a = (a + a) % n;
        b >>= 1;

    }
    return res;
}

LL QuickPow(LL a, LL b, LL n) {
    LL ans = 1;
    while(b) {
        if(b & 1) ans = Quick_Mul(ans, a, n);
        a = Quick_Mul(a, a, n);
        b >>= 1;
    }
    return ans;
}

bool Miller_Rabin(LL n) {
    if(n <= 2) {
        if(n == 2) return true;
        return false;
    }
    if(n % 2 == 0) return false;
    LL u = n - 1;
    while(u % 2 == 0) u /= 2;
    int S = 100;
    srand((LL)time(0));
    for (int i = 1; i <= S; i ++){
        LL a = rand() % (n - 2)+ 2;
        LL x = QuickPow(a, u, n);
        while(u < n) {
            LL y = QuickPow(x, 2, n);
            if(y == 1 && x != 1 && x != n - 1)
                return false;
            x = y;
            u = u * 2;
        }
        if(x != 1) return false;
    }
    return true;
}

线性基

异或下的线性基

struct LB{
    LL b[65], nb[65], tot;
    bool flag;

    void Init() {  // 初始化
        flag = false;
        tot = 0;
        memset(b, 0, sizeof(b));
        memset(nb, 0, sizeof(nb));
    }

   void Ins(LL x) { //插入
        for (int i = 62; i >= 0; i --) 
            if(x & (1LL << i)) {
                if(!b[i]) { b[i] = x; return; }
                x ^= b[i];
            }
        cout << "x: " << x << endl;
        flag = true;
    }

     bool Fin(ll x) {
        if(x == 0 && flag) return true;
        for (int i = 62; i >= 0; i --) {
            if(x >> i) {
                x ^= b[i];
            }
        }
        return x == 0;
    }

    LL getMax(LL x) { // 得到最大值
        LL res = x;
        for (int i = 62; i >= 0; i --) 
            res = max(res, res ^ b[i]);
        return res;
    }

    LL getMin(LL x) { // 得到最大值
        LL res = x;
        for (int i = 0; i <= 62; i ++)
            if(b[i]) res ^= b[i];
        return res;
    }

    LL ReBuild() { // 重新Build 为下面的Kth
        for (int i = 62; i >= 0; i --) {
            if(b[i] == 0) continue;
            for (int j = i - 1; j >= 0; j --) {
                if(b[j] == 0) continue;
                if(b[i] & (1LL << j)) b[i] ^= b[j];
            }
        }
        for (int i = 0; i <= 62; i ++) 
            if(b[i]) nb[tot++] = b[i];
    }

    LL Kth_Max(LL k) { // 得到第k大的数
        if(flag) k --;
        if(k == 0) return 0;
        LL res = 0;
        if(k >= (1LL << tot)) return -1;
        for (int i = 62; i >= 0; i --) 
            if(k & (1LL << i)) res ^= nb[i];
        return res;
    }

}lb;

void Merge(LB &a, LB b) { //合并两个线性基
    for (int i = 62; i >= 0; i--) {
        if(b.b[i] == 0) continue;
        a.Ins(b.b[i]);
    }
}

实数下的线性基

实数下的线性基类似高斯消元,如果第 j j j位为不为0,那么就把这一位当成基,并把其他的消掉,

for (int i = 1; i <= n; i ++) 
        for (int j = 1; j <= m; j ++) 
            if(fabs(x[i].value[j]) > eps) {
                if(!lb[j]) {
                    lb[j] = i;
                    break;
                }else {
                    double t = x[i].value[j] / x[lb[j]].value[j];
                    for (int k = j; k <= m; k ++) 
                        x[i].value[k] -= x[lb[j]].value[k] * t;
                }
            }
        
    

BigInt

#define MAXN 999
#define MAXSIZE 100240
#define DLEN 3

struct BigInt{
    int a[MAXSIZE],len;
    bool flag;
    
    BigInt() {
        len = 1;
        memset(a, 0, sizeof(a));
        flag = 0;
    }

    BigInt (const int b) {
        int c , d = b;
        len = 0;
        memset(a, 0, sizeof(a));
        if(!b) {
            len = 1;
            return ;
        }
        while(d) {
            a[len++] = d % (MAXN + 1);
            d /= (MAXN+1);
        }
    }

    BigInt(const char *s) {
        int t, k, index, l;
        memset(a, 0, sizeof(a));
        l = strlen(s);
        len = l/DLEN;
        if(l % DLEN) len ++;
        index = 0;
        for (int i = l - 1; i >= 0; i -= DLEN) {
            t = 0;
            k = i - DLEN + 1;
            if(k < 0) k = 0;
            for (int j = k; j <= i; j ++) t = t * 10 + s[j] - '0';
            a[index ++] = t;
        }
    }

    BigInt (const BigInt& T) {
        memset(a, 0, sizeof(a));
        len = T.len;
        for (int i = 0; i < len; i ++) a[i] = T.a[i];
    }

    bool operator < (const BigInt &T) const {
        int ln;
        if(len < T.len) return 233;
        if(len == T.len) {
            ln = len - 1;
            while(ln >= 0 && a[ln] == T.a[ln]) -- ln;
            if(ln >= 0 && a[ln] < T.a[ln]) return 233;
            return 0;
        }
        return 0;
    }

    inline bool operator < (const int &t) const {
        BigInt tee(t);
        return *this < tee;
    }

    BigInt& operator = (const BigInt &T) {
        memset(a, 0, sizeof(a));
        len = T.len;
        for (int i = 0; i < len; i ++) a[i] = T.a[i];
        return *this;
    }

    BigInt operator + (const BigInt &T) const {
        BigInt t(*this);
        int big = len;
        if(T.len > len) big = T.len;
        for (int i = 0; i < big; i ++) {
            t.a[i] += T.a[i];
            if(t.a[i] > MAXN) {
                ++t.a[i + 1];
                t.a[i] -= MAXN + 1;
            }
        }
        if(t.a[big]) t.len = big + 1;
        else t.len = big;
        return t;
    }

    BigInt operator - (const BigInt &T) const {
        int big;
        bool ctf;
        BigInt t1, t2;
        if(*this < T) {
            t1 = T;
            t2 = *this;
            ctf = 1;
        }else {
            t1 = *this;
            t2 = T;
            ctf = 0;
        }
        big = t1.len;
        int j = 0;
        for (int i = 0; i < big; i ++) {
            if(t1.a[i] < t2.a[i]) {
                j = i + 1;
                while(t1.a[j] == 0) ++j;
                -- t1.a[j--];
                while(j > i) t1.a[j --] += MAXN;
                t1.a[i] += MAXN + 1 - t2.a[i];
            }else t1.a[i] -= t2.a[i];
        }
        t1.len = big;
        while(t1.len > 1 && t1.a[t1.len - 1] == 0) {
            -- t1.len;
            -- big;
        }
        if(ctf) t1.a[big - 1] = -t1.a[big - 1];
        return t1;
    }

    BigInt operator * (const BigInt &T) const {
        BigInt res;
        int up;
        int te, tee;
        for (int i = 0; i < len; i ++) {
            up = 0;
            for (int j = 0; j < T.len; j ++) {
                te = a[i] * T.a[j] + res.a[i + j] + up;
                if(te > MAXN) {
                    tee = te - te / (MAXN + 1) * (MAXN + 1);
                    up = te / (MAXN + 1);
                    res.a[i + j] = tee;
                }else {
                    up = 0;
                    res.a[i + j] = te;
                }
            }
            if(up) res.a[i + T.len] = up;
        }
        res.len = len + T.len;
        while(res.len > 1 && res.a[res.len - 1] == 0) -- res.len;
        return res;
    }
    
  
    BigInt operator / (const int &b) {
        BigInt res;
        int sum = 0, newlen = 0;
        for (int i = len-1; i >= 0; i --) {
            sum = sum * (MAXN+1) + a[i];
            if(sum < b) res.a[i] = 0;
            else {
                if(!newlen) newlen = i + 1;
                res.a[i] = sum / b;
                sum %= b;
            }
        }
        res.len = max(newlen, 1);
        return res;
    }

    int operator % (const int &b) const {
        int d = 0;
        for (int i = len - 1; i >= 0; i --)
            d = (d * (MAXN + 1) % b + a[i]) % b;
        return d;
    }

    BigInt operator ^ (const int &n) const {
        BigInt t(n), res(1);
        int y = n;
        while(y) {
            if(y & 1) res = res * t;
            t = t * t;
            y >>= 1;
        }
        return res;
    }

    inline void print() {
        printf("%d", a[len - 1]);
        for (int i = len - 2; i >= 0; i --)
            printf("%03d", a[i]);
        printf("\n");
    }
};

fft求高精度快速幂

#include
using namespace std;

#define ll long long
const int maxn = 1e5 + 5;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;
typedef complex<double> cp;
const double PI = acos(-1);
#define MAXN 999
#define MAXSIZE 100240
#define DLEN 3


int n, c[maxn], rnk[maxn];
cp omg[maxn], inv[maxn];

void init(int n) {
    memset(rnk, 0, sizeof(rnk));
    int lim = 0;
    while((1<<lim) < n) lim ++;
    for (int i = 0; i < n; i ++) {
        omg[i] = cp(cos(2*PI*i/n), sin(2*PI*i/n));
        inv[i] = conj(omg[i]);
        for (int j = 0; j < lim; j ++) 
            if((i>>j) & 1) rnk[i] |= (1<<(lim-j-1));
    }
}

void fft(cp *a, cp *omg, int n) {
    for (int i = 0; i < n; i ++) 
        if(i < rnk[i]) swap(a[i], a[rnk[i]]);
    for (int l = 2; l <= n; l *= 2) {
        int m = l/2;
        for (cp *p = a; p != a + n; p += l) 
            for (int i = 0; i < m; i ++) {
                cp t = omg[n/l*i] * p[i+m];
                p[i+m] = p[i] - t;
                p[i] += t;
            }
    }
}

struct BigInt{
    int a[MAXSIZE],len;
    
    BigInt() {
        len = 1;
        memset(a, 0, sizeof(a));
    }

    BigInt (const int b) {
        int c , d = b;
        len = 0;
        memset(a, 0, sizeof(a));
        if(!b) {
            len = 1;
            return ;
        }
        while(d) {
            a[len++] = d % (MAXN + 1);
            d /= (MAXN+1);
        }
    }

    BigInt(const char *s) {
        int t, k, index, l;
        memset(a, 0, sizeof(a));
        l = strlen(s);
        len = l/DLEN;
        if(l % DLEN) len ++;
        index = 0;
        for (int i = l - 1; i >= 0; i -= DLEN) {
            t = 0;
            k = i - DLEN + 1;
            if(k < 0) k = 0;
            for (int j = k; j <= i; j ++) t = t * 10 + s[j] - '0';
            a[index ++] = t;
        }
    }


    BigInt& operator = (const BigInt &T) {
        memset(a, 0, sizeof(a));
        len = T.len;
        for (int i = 0; i < len; i ++) a[i] = T.a[i];
        return *this;
    }

    void operator *= (const BigInt &T) {
        static cp la[maxn], lb[maxn];
        int newlen = len + T.len - 1, n = 1;
        while(n < newlen) n <<= 1;
        for (int i = 0; i < n; i ++) {
            la[i] = cp(i < len ? a[i] : 0, 0);
            lb[i] = cp(i < T.len ? T.a[i] : 0, 0);
        } 
        init(n);
        fft(la, omg, n); fft(lb, omg, n);
        for (int i = 0; i < n; i ++) la[i] *= lb[i];
        fft(la, inv, n);
        for (int i = 0; i < newlen; i ++) 
            a[i] = floor(la[i].real()/n+0.5);
        a[len=newlen]=0;
        for (int i = 0; i < len; i ++) {
            a[i+1] += a[i] / (MAXN + 1);
            a[i] %= (MAXN + 1);
        }
        if(a[len]) len ++;
    }
    
    BigInt operator / (const int &b) {
        BigInt res;
        int sum = 0, newlen = 0;
        for (int i = len-1; i >= 0; i --) {
            sum = sum * (MAXN+1) + a[i];
            if(sum < b) res.a[i] = 0;
            else {
                if(!newlen) newlen = i + 1;
                res.a[i] = sum / b;
                sum %= b;
            }
        }
        res.len = max(newlen, 1);
        return res;
    }

    int operator % (const int &b) const {
        int d = 0;
        for (int i = len - 1; i >= 0; i --)
            d = (d * (MAXN + 1) % b + a[i]) % b;
        return d;
    }

    inline void print() {
        printf("%d", a[len - 1]);
        for (int i = len - 2; i >= 0; i --)
            printf("%03d", a[i]);
        printf("\n");
    }
}ret, a;
int main() {
    int x;
    scanf("%d", &x);
    ret = BigInt(1); a = BigInt(2);
    while(x) {
        if(x & 1) ret *= a;
        a *= a;
        x >>= 1;
    }
    ret.print();
    return 0;
}

倍增

#include

using namespace std;

#define LL long long
#define ull unsigned long long
#define INF 0x3f3f3f3f
#define maxn 200005
#define eps 0.00000001
#define PI acos(-1.0)
#define M 1000000007

struct Edge{
    int v, nxt, w;
}edge[maxn << 1];

int tot, head[maxn];
int grand[maxn][30], gx[maxn][30], dis[maxn];
int n, q;


void init() {
    tot = 0;
    memset(head, -1, sizeof(head));
    memset(grand, 0, sizeof(grand));
    memset(gx, 0, sizeof(gx));
    
}

void addEdge(int u, int v, int w) {
    edge[tot].v = v;
    edge[tot].w = w;
    edge[tot].nxt = head[u];
    head[u] = tot ++;
    
    edge[tot].v = u;
    edge[tot].w = w;
    edge[tot].nxt = head[v];
    head[v] = tot ++;
}

void bfs(int root) {
    memset(dis, -1, sizeof(dis));
    dis[root] = 1;
    queue<int> que;
    que.push(root);
    while (!que.empty()) {
        int u = que.front(); que.pop();
        for (int i = head[u]; i + 1; i = edge[i].nxt) {
            int son = edge[i].v;
            if(dis[son] == -1) {
                dis[son] = dis[u] + 1;
                grand[son][0] = u;
                gx[son][0] = edge[i].w;
                que.push(son);
                for (int j = 1; (1 << j) <= n; j ++) {
                    grand[son][j] = grand[grand[son][j - 1]][j - 1];
                    gx[son][j] = gx[son][j - 1] + gx[grand[son][j - 1]][j - 1];
                }
            }
        }
    }
}

int LCA(int a, int b) {
    int ans = 0;
    if(dis[a] < dis[b]) swap(a, b);
    int dd = dis[a] - dis[b];
    for (int i = 0; (dd >> i); i ++)
        if((dd >> i) & 1) {
            ans += gx[a][i];
            a = grand[a][i];
        }
    for (int i = log2(n) + 1; i >= 0; i --)
        if(grand[a][i] != grand[b][i]) {
            ans += gx[a][i] + gx[b][i];
            a = grand[a][i];
            b = grand[b][i];
        }
    if(a == b) return ans;
    ans += gx[a][0] + gx[b][0];
    return ans ;
}

约瑟夫问题

//N 个人, 第K 淘汰
LL Josephus(LL N, LL K) {
    if(N == 1) return 0;
    if(N < K) {
        LL ret = 0;
        for (LL i = 2; i <= N; i ++)
            ret = (ret + K) % i;
        return ret;
    }
    LL ret = Josephus(N - N/K, K);
    if(ret < N % K) ret = ret - N % K + N;
    else ret = ret - N % K + (ret - N % K) / (K - 1);
    return ret;
}

中国剩余定理

p = ∏ i = 1 k p i p=\prod\limits_{i=1}^{k}p_i p=i=1kpi
{ x 1 ≡ m 1 ( m o d    p 1 ) x 2 ≡ m 2 ( m o d    p 2 ) . . . x k ≡ m k ( m o d    p k ) \begin{cases}x_1\equiv m_1 (\mod p_1) \\ x_2 \equiv m_2(\mod p_2)\\ ...\\ x_k \equiv m_k(\mod p_k)\end{cases} x1m1(modp1)x2m2(modp2)...xkmk(modpk)
X = ∑ i = 1 k m i ⋅ ( p p i ) ∗ i n v ( p p i , p i ) X=\sum\limits_{i=1}^{k}m_i\cdot(\frac{p}{p_i})*inv(\frac{p}{p_i}, p_i) X=i=1kmi(pip)inv(pip,pi)

扩展中国剩余定理

一般的,中国剩余定理的模数p是互素的,但对于互素的情况就要用到扩展中国剩余定理

LL M[maxn], C[maxn];
//模数, 余数
LL mul(LL a, LL b, LL p) {
    if(b < 0) b = -b;
    LL ans = 0;
    while(b) {
        if(b & 1) ans = (ans + a) % p;
        a = (a + a) % p;
        b >>= 1;
    }
    return ans;
}

LL gcd(LL a, LL b) {
    return !b ? a : gcd(b, a %b);
}

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

LL getInv(LL a, LL p) {
    LL x, y;
    exgcd(a, p, x, y);
    x = (x % p + p) % p;
    return x;
}

LL exCrt() {
    for (LL i = 2; i <= n; i ++) {
        LL M1 = M[i - 1], M2 = M[i];
        LL C1 = C[i - 1], C2 = C[i];
        LL T = gcd(M1, M2);
        LL t = (C2 - C1 % M2 + M2) % M2;
        if(t % T) return -1;
        M[i] = M1 / T * M2;
        C[i] = mul(getInv(M1 / T, M2 / T), t / T, (M2 / T));
        C[i] = C[i] * M1 + C1;
        C[i] = (C[i] % M[i] + M[i]) % M[i];
    }
    return C[n];
}

卢卡斯

LL  exgcd(LL a, LL b, LL &x, LL &y)
{
    if (b == 0)
    {
        x = 1;
        y = 0;
        return a;
    }
    LL ans = exgcd(b, a % b, x, y);
    LL temp = x;
    x = y;
    y = temp - (a / b) * y;
    return ans;
}
LL inv(LL a)
{
    LL x, y;
    LL t = exgcd(a, M, x, y);
    if (t != 1)
    {
        return -1;
    }
    return (x % M + M) % M;
}
 
LL fac[maxn];
void getfac()
{
    fac[0] = 1;
    for (int i = 1; i < maxn; i++)
    {
        fac[i] = fac[i - 1] * i % M;
    }
}
LL C(LL n, LL m)
{
    if (n < 0 || m < 0|| n < m)
    {
        return 0;
    }
    return fac[n] * inv(fac[m]) % M * inv(fac[n - m]) % M;
}
LL lucas(LL n, LL m)
{
    if (m == 0)
    {
        return 1;
    }
    return (lucas(n / M, m / M) * C(n % M, m % M)) % M;
}

扩展卢卡斯

LL Pre[maxn];

LL extend_gcd(LL a, LL b, LL &x, LL &y) {
    if(!b) {
        x = 1; y = 0;
        return a;
    }
    LL d = extend_gcd(b, a % b, x, y);
    LL t = x;
    x = y; y = t - (a / b) * y;
    return d;
}

LL mul(LL a, LL b, LL P){
    LL L = a * (b >> 25LL) % P * (1LL << 25) % P;
    LL R = a * (b & ((1LL << 25) - 1)) % P;
    return (L + R) % P;
}

LL Pow(LL a, LL b, LL P) {
    LL ans = 1; a %= P;
    while(b) {
        if(b & 1) ans = mul(ans, a, P);
        a = mul(a, a, P);
        b >>= 1;
    }
    return ans;
}

LL getInv(LL a, LL p) {
    LL x, y;
    extend_gcd(a, p, x, y);
    x = (x % p + p) % p;
    return x;
}

LL CRT(LL m, LL p, LL P) {
    return mul(mul(m, (P / p), P), getInv(P / p, p), P);
}

void init(LL pi, LL pk) {
    Pre[0] = 1;
    for (int i = 1; i <= pk; i ++) {
        Pre[i] = Pre[i - 1];
        if(i % pi) Pre[i] = mul(Pre[i], i, pk);
    }
}

LL Mul(LL n, LL pi, LL pk) {
    if(n <= 1) return 1;
    LL ans = Pow(Pre[pk], n / pk, pk);
    if(n % pk) ans = mul(ans, Pre[n % pk], pk);
    return mul(ans, Mul(n / pi, pi, pk), pk);
}

LL C(LL n, LL m, LL pi, LL pk) {
    if(n < m) return 0;
    init(pi, pk);
    LL r = 0;
    for(LL i = n; i; i /= pi) r += i / pi;
    for(LL i = m; i; i /= pi) r -= i / pi;
    for(LL i = n - m; i; i /= pi) r -= i / pi;
    LL a = Mul(n, pi, pk);
    LL b = getInv(Mul(m, pi, pk), pk);
    LL c = getInv(Mul(n - m, pi, pk), pk);
    LL ans = mul(mul(a, b, pk), c, pk);
    return mul(ans, Pow(pi, r, pk), pk);
}

LL ex_lucas(LL n, LL m, LL P) {
//C_n^m %p
    LL ans = 0;
    LL p = P;
    for (int i = 2; i <= P; i ++) {
        if(p % i == 0) {
            LL pi = i, pk = 1;
            while(p % i == 0) {
                p /= i;
                pk *= i;
            }
            ans = (ans + CRT(C(n, m, pi, pk), pk, P)) % P;
        }
    }
    return ans;
}

指数循环

A B % P = A B % φ ( P ) + φ ( P ) % P A^B\%P=A^{B\%\varphi(P)+\varphi(P)}\%P AB%P=AB%φ(P)+φ(P)%P

BSGS

A n ≡ B ( m o d    M ) A n = A i S − j A i S − j ≡ B ( m o d    M ) A i s ≡ B ⋅ A j ( m o d    M ) 另 一 种 : A j ≡ B ⋅ A − i S ( m o d    M ) A^n\equiv B(\mod M)\\ A^n=A^{iS-j}\\ A^{iS-j}\equiv B(\mod M)\\ A^{is}\equiv B\cdot A^j(\mod M)\\ 另一种:\\ A^j \equiv B \cdot A^{-iS}(\mod M) AnB(modM)An=AiSjAiSjB(modM)AisBAj(modM)AjBAiS(modM)

map<LL, LL> Hash;

LL Mul(LL a, LL b, LL p) {
    LL L = a * (b >> 25LL) % p * (1LL << 25) % p;
    LL R = a * (b & ((1LL << 25) - 1)) % p;
    return (L + R) % p;
}

LL Pow(LL a, LL b, LL p) {
    a %= p;
    LL res = 1;
    while(b) {
        if(b & 1) res = Mul(res, a, p);
        a = Mul(a, a, p);
        b >>= 1;
    }
    return res;
}
/*
get ans for a^ans = b % p
*/
LL BSGS(LL a, LL b, LL p) {
    LL m = sqrt(p) + 1;
    LL res = 1;
    for (int j = 0; j <= m; j ++) {
        Hash[Mul(b, res, p)] = j;
        res = Mul(res, a, p);
    }
    for (int i = 1; i <= m; i ++) {
        LL k = Pow(a, i * m, p);
        if(Hash.count(k))
            return i * m - Hash[k];
    }
}

莫比乌斯反演

  • 莫比乌斯反演恒等式
    如 果 有 : F ( n ) = ∑ d ∣ n f ( d ) 那 么 : f ( n ) = ∑ d ∣ n μ ( d ) F ( n d ) 如果有:F(n)=\sum\limits_{d|n}f(d)\\ 那么:f(n)=\sum\limits_{d|n}\mu(d)F(\frac{n}{d}) F(n)=dnf(d)f(n)=dnμ(d)F(dn)
  • 莫比乌斯函数
    μ ( 1 ) = 1 , μ ( n ) = μ ( p 1 k 1 ) μ ( p 2 k 2 ) . . . μ ( p n k n ) = { ( − 1 ) k , k 1 = k 2 = . . . = k n = 1 0 , o t h e r w i s e \mu(1)=1,\mu(n)= \mu(p_1^{k_1})\mu(p_2^{k_2})...\mu(p_n^{k_n})=\begin{cases} (-1)^k ,k_1=k_2=...=k_n=1\\ 0 ,otherwise \end{cases} μ(1)=1μ(n)=μ(p1k1)μ(p2k2)...μ(pnkn)={(1)kk1=k2=...=kn=10otherwise
  • 定理:
    • θ \theta θ可乘, μ θ \mu\theta μθ可乘, ∑ d ∣ n μ ( d ) θ ( d ) \sum\limits_{d|n}\mu(d)\theta(d) dnμ(d)θ(d)也可乘,从而 ∑ d ∣ n μ ( d ) θ ( d ) = ( 1 − θ ( p 1 ) ) ( 1 − θ ( p 2 ) ) . . . ( 1 − θ ( p k ) ) \sum\limits_{d|n}\mu(d)\theta(d)=(1-\theta(p_1))(1-\theta(p_2))...(1-\theta(p_k)) dnμ(d)θ(d)=(1θ(p1))(1θ(p2))...(1θ(pk))
    • θ ≡ 1 , ∑ d ∣ n μ ( d ) = { 1 , n = 1 0 , o t h e r w i s e \theta \equiv 1,\sum\limits_{d|n}\mu(d)=\begin{cases}1, n=1\\0, otherwise\end{cases} θ1,dnμ(d)={1,n=10,otherwise
    • θ = 1 d , ∑ d ∣ n μ ( d ) = ( 1 − 1 p 1 ) ( 1 − 1 p 2 ) . . . \theta=\frac{1}{d},\sum\limits_{d|n}\mu(d)=(1-\frac{1}{p_1})(1-\frac{1}{p_2})... θ=d1,dnμ(d)=(1p11)(1p21)...

积性函数

  • 常见的积性函数
    • I ( n ) : 不 变 的 函 数 , 定 义 为 I ( n ) = 1 ( 完 全 积 性 ) I(n): 不变的函数,定义为I(n)=1(完全积性) I(n):I(n)=1
    • I d ( n ) : 单 位 函 数 , 定 义 为 I d ( n ) = n ( 完 全 积 性 ) Id(n):单位函数,定义为Id(n)=n(完全积性) Id(n):Id(n)=n()
    • I d k ( n ) : 幂 函 数 , 定 义 为 I d k ( n ) = n k ( 完 全 积 性 ) Idk(n):幂函数,定义为Idk(n)=n^k(完全积性) Idk(n):Idk(n)=nk()
    • e ( n ) : e ( n ) = { 1 , n = 1 0 , o t h e r w i s e , 别 称 为 " 对 于 迪 利 克 雷 卷 积 的 乘 法 单 位 " ( 完 全 积 性 ) e(n):e(n)=\begin{cases}1,n=1\\0,otherwise\end{cases},别称为"对于迪利克雷卷积的乘法单位"(完全积性) e(n):e(n)={1,n=10,otherwise,""
    • μ ( n ) : 莫 比 乌 斯 函 数 \mu(n):莫比乌斯函数 μ(n):
    • φ ( n ) : 欧 拉 函 数 \varphi(n):欧拉函数 φ(n)
    • d ( n ) : 一 个 数 n 的 约 数 个 数 d(n): 一个数n的约数个数 d(n):n
    • σ ( n ) : 一 个 数 n 的 约 数 和 \sigma(n): 一个数n的约数和 σ(n):n

迪利克雷卷积

  • 定义: ( f ∗ g ) ( n ) = ∑ d ∣ n f ( d ) g ( n d ) (f*g)(n)=\sum\limits_{d|n}f(d)g(\frac{n}{d}) (fg)(n)=dnf(d)g(dn)
  • 常见的迪利克雷卷积:
    • d ( n ) = ∑ d ∣ n 1 , 即 d = 1 ∗ 1 d(n)=\sum\limits_{d|n}1,即d=1*1 d(n)=dn1,d=11
    • σ ( n ) = ∑ d ∣ n d 即 σ = d ∗ 1 \sigma(n)=\sum\limits_{d|n}d即\sigma=d*1 σ(n)=dndσ=d1
    • φ ( n ) = ∑ d ∣ n μ ( d ) ( n d ) 即 φ = μ ∗ I d \varphi(n)=\sum\limits_{d|n}\mu(d)(\frac{n}{d})即\varphi=\mu * Id φ(n)=dnμ(d)(dn)φ=μId
    • e ( n ) = ∑ d ∣ n μ ( d ) 即 e = μ ∗ 1 e(n)=\sum\limits_{d|n}\mu(d)即e=\mu * 1 e(n)=dnμ(d)e=μ1
    • n = ∑ d ∣ n φ ( d ) 即 I d = φ ∗ 1 n=\sum\limits_{d|n}\varphi(d)即Id=\varphi * 1 n=dnφ(d)Id=φ1
    • e ( n ) = ∑ d ∣ n μ ( d ) e(n)=\sum\limits_{d|n}\mu(d) e(n)=dnμ(d)

杜教筛

S ( n ) = ∑ i = 1 n f ( i ) S(n)=\sum\limits_{i=1}^nf(i) S(n)=i=1nf(i)

找 一 个 合 适 的 函 数 g 找一个合适的函数g g
g ( 1 ) S ( n ) = ∑ i = 1 n ( f ∗ g ) ( i ) − ∑ i = 2 n g ( d ) S ( ⌊ n d ⌋ ) g(1)S(n)=\sum\limits_{i=1}^n(f*g)(i)-\sum\limits_{i=2}^ng(d)S(\lfloor\frac{n}{d}\rfloor) g(1)S(n)=i=1n(fg)(i)i=2ng(d)S(dn)

− − − − − − − − − − − − − − − − − − − − − − − − − − − − − − ------------------------------

∑ i = 1 n ∑ j = 1 n gcd ⁡ ( i , j ) \sum\limits_{i=1}^{n}\sum\limits_{j=1}^{n}\gcd(i,j) i=1nj=1ngcd(i,j)
= ∑ i = 1 n ∑ j = 1 n d [ gcd ⁡ ( i , j ) = d ] =\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{n}d[\gcd(i,j)=d] =i=1nj=1nd[gcd(i,j)=d]
= ∑ d = 1 n d ∑ i = 1 ⌊ n d ⌋ ∑ j = 1 ⌊ n d ⌋ [ gcd ⁡ ( i , j ) = 1 ] =\sum\limits_{d=1}^{n}d\sum\limits_{i=1}^{\lfloor{\frac{n}{d}}\rfloor}\sum\limits_{j=1}^{\lfloor{\frac{n}{d}}\rfloor}[\gcd(i,j)=1] =d=1ndi=1dnj=1dn[gcd(i,j)=1]
而 gcd ⁡ ( i , j ) = 1 等 同 于 ∑ k ∣ gcd ⁡ ( i , j ) μ ( k ) 而\gcd(i,j)=1等同于\sum\limits_{k|\gcd(i,j)}\mu(k) gcd(i,j)=1kgcd(i,j)μ(k)
所 以 原 式 = ∑ d = 1 n d ∑ i = 1 ⌊ n d ⌋ ∑ j = 1 ⌊ n d ⌋ ∑ k ∣ gcd ⁡ ( i , j ) μ ( k ) 所以原式=\sum\limits_{d=1}^{n}d\sum\limits_{i=1}^{\lfloor{\frac{n}{d}}\rfloor}\sum\limits_{j=1}^{\lfloor{\frac{n}{d}}\rfloor}\sum\limits_{k|\gcd(i,j)}\mu(k) =d=1ndi=1dnj=1dnkgcd(i,j)μ(k)
把 k 提 到 前 面 把k提到前面 k
原 式 = ∑ d = 1 n d ∑ k = 1 ⌊ n d ⌋ μ ( k ) ∑ i = 1 ⌊ n k d ⌋ ∑ j = 1 ⌊ n k d ⌋ 1 设 函 数 S ( n ) = ∑ i = 1 n ∑ j = 1 n 1 原 式 = ∑ d = 1 n d ∑ k = 1 ⌊ n d ⌋ μ ( k ) S ( n k d ) 令 T = k d , 原 式 = ∑ T = 1 n S ( n T ) ∑ k ∣ T μ ( k ) T k 因 为 μ ∗ i d = φ ( ∗ 为 狄 利 克 雷 卷 积 ) 所 以 原 式 = ∑ T = 1 n S ( n T ) φ ( T ) 原式=\sum\limits_{d=1}^{n}d\sum\limits_{k=1}^{\lfloor{\frac{n}{d}}\rfloor}\mu(k)\sum\limits_{i=1}^{\lfloor{\frac{n}{kd}}\rfloor}\sum\limits_{j=1}^{\lfloor{\frac{n}{kd}}\rfloor}1\\ 设函数S(n) = \sum\limits_{i=1}^{n}\sum\limits_{j=1}^{n}1\\ 原式=\sum\limits_{d=1}^{n}d\sum\limits_{k=1}^{\lfloor{\frac{n}{d}}\rfloor}\mu(k)S(\frac{n}{kd})\\ 令T=kd, 原式=\sum\limits_{T=1}^{n}S(\frac{n}{T})\sum\limits_{k|T}\mu(k)\frac{T}{k}\\ 因为\mu*id=\varphi (*为狄利克雷卷积)\\ 所以 原式=\sum\limits_{T=1}^{n}S(\frac{n}{T})\varphi(T) =d=1ndk=1dnμ(k)i=1kdnj=1kdn1S(n)=i=1nj=1n1=d=1ndk=1dnμ(k)S(kdn)T=kd,=T=1nS(Tn)kTμ(k)kTμid=φ()=T=1nS(Tn)φ(T)
那么结果就显而易见了,结果就是欧拉函数的和,但是我们发现这个n是1e10的大小,线性筛会超时,所以欧拉函数的前缀和我们需要用杜教筛来求得,
我们知道 ϕ ∗ I = i d \phi*I=id ϕI=id,所以我们可以直接套杜教筛的公式
S ( n ) = ∑ i = 1 n φ ( i ) g ( 1 ) S ( n ) = ∑ i = 1 n ( g ∗ S ) ( n ) − ∑ i = 2 n g ( i ) S ( ⌊ n i ⌋ ) S(n)=\sum\limits_{i=1}^{n}\varphi(i) \\g(1)S(n)=\sum\limits_{i=1}^{n}(g*S)(n)-\sum\limits_{i=2}^{n}g(i)S(\lfloor{\frac{n}{i}}\rfloor) S(n)=i=1nφ(i)g(1)S(n)=i=1n(gS)(n)i=2ng(i)S(in)
g函数为 I I I
那么原式= ∑ i = 1 n i − ∑ i = 2 n S ( ⌊ n i ⌋ ) = n ( n + 1 ) 2 − ∑ i = 2 n S ( ⌊ n i ⌋ ) \sum\limits_{i=1}^{n}i-\sum\limits_{i=2}^{n}S(\lfloor{\frac{n}{i}}\rfloor)\\ =\frac{n(n+1)}{2}-\sum\limits_{i=2}^{n}S(\lfloor{\frac{n}{i}}\rfloor) i=1nii=2nS(in)=2n(n+1)i=2nS(in)
对于杜教筛我们可以预先处理 n 2 3 n^{\frac{2}{3}} n32的结果,然后后面的用杜教筛公式递归求得

#include 

using namespace std;
#define LL long long
const int M = 5e6;
const int Mod = 1e9 +7;
const double eps = 0.000000001;
LL phi[M + 30], prim[M + 30], tot;
bool mark[M + 30];
map<LL, LL> m;
#define inv_2 (Mod+1)/2

LL Add(LL a, LL b) {
    LL c = (a + b) % Mod;
    if(c >= Mod) return c - Mod;
    if(c < 0) return c + Mod;
    return c;
}

void init() {
    phi[1] = 1;
    for(LL i = 2; i <= M; i ++) {
        if(!mark[i]) {
            prim[++tot] = i;
            phi[i] = i - 1;
        }
        for (LL j = 1; j <= tot; j ++) {
            if(i * prim[j] > M) break;
            mark[i * prim[j]] = 1;
            if(i % prim[j] == 0) {
                phi[i * prim[j]] = phi[i] * prim[j];
                break;
            }
            phi[i *prim[j]] = phi[i] * phi[prim[j]];
        }
    }
    for (int i = 1; i <= M; i ++) phi[i] = Add(phi[i-1], phi[i]);
}

LL getPhi(LL n) {
    if(n <= M) return phi[n];
    if(m[n]) return m[n];
    LL ans;
    ans = 1LL * n % Mod * (n % Mod + 1) % Mod * inv_2 % Mod;
    for (LL l = 2, r; l <= n; l = r + 1) {
        r = n/(n/l);
        ans = (ans - (r - l + 1) % Mod * getPhi(n/l) % Mod + Mod) % Mod;
    }
    return m[n] = ans;
}
LL solve(LL n) {
    LL ans = 0;
    for (LL l = 1, r; l <= n; l = r + 1) {
        r = n/(n/l);
        ans = Add(ans, 1ULL * (n/l) % Mod * (n/l) % Mod * (Add(getPhi(r) % Mod, -getPhi(l-1) % Mod)  ) % Mod);
    }
    return ans;
}

int main()
{
    init();
    LL n;
    cin >> n;
    m.clear();
    cout << solve(n) << endl;
    return 0;
}

Min_25筛

M i n _ 25 Min\_{25} Min_25的使用条件:
对于积性函数 F ( x ) F(x) F(x),求 ∑ x = 1 n F ( x ) \sum\limits_{x=1}^nF(x) x=1nF(x)

F ( x ) F(x) F(x) 满足 F ( p ) F(p) F(p) 可以用多项式表示,且可以快速求出 F ( p k ) ( p 指 质 数 ) F(p^k)(p 指质数) F(pk)p

套路:
g ( n , j ) = { g ( n , j − 1 ) , P j 2 > n g ( n , j − 1 ) − f ( P j ) [ g ( n P j , j − 1 ) − ∑ i = 1 j − 1 f ( P i ) ] , P j 2 < = n g(n,j)=\begin{cases}g(n,j-1),P_j^2>n\\g(n,j-1)-f(P_j)[g(\frac{n}{P_j},j-1)-\sum\limits_{i=1}^{j-1}f(P_i)], P_j^2<=n\end{cases} g(n,j)=g(n,j1),Pj2>ng(n,j1)f(Pj)[g(Pjn,j1)i=1j1f(Pi)],Pj2<=n

S ( n , x ) = g ( n ) − ∑ i = 1 j − 1 f ( P i ) + ∑ p k e < = n & & k > = x f ( p k e ) ( S ( n p k e , x + 1 ) + [ e ! = 1 ) S(n,x)=g(n)-\sum\limits_{i=1}^{j-1}f(P_i)+\sum\limits_{p_k^e<=n\&\&k>=x}f(p_k^e)(S(\frac{n}{p_k^e},x+1)+[e!=1) S(n,x)=g(n)i=1j1f(Pi)+pke<=n&&k>=xf(pke)(S(pken,x+1)+[e!=1)
以洛谷P5325 为例:
积性函数 f ( x ) f(x) f(x),且 f ( p k ) = p k ( p k − 1 ) f(p^k)=p^k(p^k-1) f(pk)=pk(pk1)
∑ i = 1 n f ( i ) \sum\limits_{i=1}^nf(i) i=1nf(i)
f ( p ) = p ( p − 1 ) = p 2 − p f(p)=p(p-1)=p^2-p f(p)=p(p1)=p2p
设 g ( x ) = x 2 , h ( x ) = x , f ( x ) = g ( x ) − h ( x ) 设g(x)=x^2,h(x)=x,f(x)=g(x)-h(x) g(x)=x2,h(x)=x,f(x)=g(x)h(x)

#include

using namespace std;

#define LL long long
const int maxn = 1e6 + 5;
const int inf = 0x3f3f3f3f;
const int Mod = 1e9 + 7;
const double eps = 1e-8;
typedef pair<int, int> psi;
#define inv_2 (Mod+1)/2
#define inv_6 (Mod+1)/6
LL sqr, m, w[maxn], g[maxn], h[maxn];
LL sumg[maxn], sumh[maxn], id1[maxn], id2[maxn];
LL prim[maxn], tot;
bool mark[maxn];

LL Add(LL a, LL b) {
    return (a + b) % Mod;
}

LL Sup(LL a, LL b) {
    return (a - b + Mod) % Mod;
}

LL Pow(LL a, LL b) {
    LL res = 1;
    while(b) {
        if(b & 1) res = res * a % Mod;
        a = a * a % Mod;
        b >>= 1;
    }
    return res;
}

void init(LL n) {
    mark[1] = 1;
    for (LL i = 2; i <= n; i ++) {
        if(!mark[i]) {
            prim[++tot] = i;
            sumg[tot] = (sumg[tot-1] + i * i) % Mod;
            sumh[tot] = (sumh[tot-1] + i) % Mod;
        }
        for (LL j = 1; j <= tot; j ++) {
            if(i * prim[j] > n) break;
            mark[i * prim[j]] = 1;
            if(i % prim[j] == 0) break;
        }
    }
}

void GetW(LL n) {
    for (LL i = 1, j; i <= n; i = j + 1) {
        j = n / (n / i);
        w[++m] = n / i;
        LL t = w[m] % Mod;
        g[m] = t * (t + 1) % Mod * ((2LL * t + 1) % Mod) % Mod * inv_6 % Mod;
        g[m] --;
        h[m] = t * (t + 1) % Mod * inv_2 % Mod;
        h[m] --;
        if(w[m] <= sqr) id1[w[m]] = m;
        else id2[n/w[m]] = m;
    }
}

void GetG(LL n) {
    for (LL i = 1; i <= tot; i ++) {
        for (LL j = 1; j <= m && prim[i] * prim[i] <= w[j]; j ++) {
            LL d = w[j] / prim[i];
            LL id = d <= sqr ? id1[d] : id2[n/d];
            g[j] = Sup(g[j], prim[i] * prim[i] % Mod * ((g[id] - sumg[i-1] + Mod) % Mod) % Mod);
            h[j] = Sup(h[j], prim[i] * ((h[id] - sumh[i-1] + Mod) % Mod) % Mod);
        }
    }
}

LL S(LL x, LL y, LL n) {
    if(x <= prim[y-1] || x <= 1) return 0;
    LL id = x <= sqr ? id1[x] : id2[n/x];
    LL res = (g[id] - h[id] + Mod - sumg[y-1] + sumh[y-1] + Mod) % Mod;
    for (LL i = y; i <= tot && prim[i] * prim[i] <= x; i ++) {
        LL t = prim[i];
        for (LL j = 1; t <= x; j ++, t = t * prim[i]) {
            LL p1 = t % Mod;
            res = Add(res, p1 * (p1 - 1) % Mod * (S(x/t, i+1, n) + (j != 1)) % Mod);
        }
    }
    return res % Mod;
}

int main(int argc, char *args[]) {
    LL n;
    scanf("%lld", &n);
    sqr = sqrt(n);
    init(sqr);
    GetW(n);
    GetG(n);
    printf("%lld\n", (S(n, 1, n) + 1) % Mod);
    return 0;
}


组合数

  • 排列
    A n m = ( n − m + 1 ) A n m − 1 A_n^m=(n-m+1)A_n^{m-1} Anm=(nm+1)Anm1

    A n m = n n − m A n − 1 m A_n^m=\frac{n}{n-m}A_{n-1}^{m} Anm=nmnAn1m

    A n m = n A n − 1 m − 1 A_n^m=nA_{n-1}^{m-1} Anm=nAn1m1

    n A n n = A n + 1 n + 1 − A n n nA_n^n=A_{n+1}^{n+1}-A_n^n nAnn=An+1n+1Ann

    A n + 1 m = A n m + m A n m − 1 A_{n+1}^m=A_n^m+mA_n^{m-1} An+1m=Anm+mAnm1

    1 ! + 2 ⋅ 2 ! + 3 ⋅ 3 ! + . . . + n ⋅ n ! = ( n + 1 ) ! − 1 1!+2\cdot2!+3\cdot3!+...+n\cdot n!=(n+1)!-1 1!+22!+33!+...+nn!=(n+1)!1

    A n m = ( n − m + 1 ) A n m − 1 A_n^m=(n-m+1)A_n^{m-1} Anm=(nm+1)Anm1

    A n m = ( n − m + 1 ) A n m − 1 A_n^m=(n-m+1)A_n^{m-1} Anm=(nm+1)Anm1

  • 组合

  • C n 2 = n ( n − 1 ) 2 C_n^2=\frac{n(n-1)}{2} Cn2=2n(n1)

    C n 3 = n ( n − 1 ) ( n − 2 ) 6 C_n^3=\frac{n(n-1)(n-2)}{6} Cn3=6n(n1)(n2)

    C n m = C n − 1 m − 1 + C n − 1 m C_n^m=C_{n-1}^{m-1}+C_{n-1}^m Cnm=Cn1m1+Cn1m

    m C n m = n C n − 1 m − 1 mC_n^m=nC_{n-1}^{m-1} mCnm=nCn1m1

    C n m = n n − m C n − 1 m C_n^m=\frac{n}{n-m}C_{n-1}^m Cnm=nmnCn1m

    C n m = n m C n − 1 m − 1 C_n^m=\frac{n}{m}C_{n-1}^{m-1} Cnm=mnCn1m1

    C n m = m + 1 n − m C n m + 1 = n − m + 1 m C n m − 1 C_n^m=\frac{m+1}{n-m}C_n^{m+1}=\frac{n-m+1}{m} C_n^{m-1} Cnm=nmm+1Cnm+1=mnm+1Cnm1

    C r r + C r + 1 r + C r + 2 r + . . . + C n r = C n + 1 r + 1 C_r^r+C_{r+1}^r+C_{r+2}^r+...+C_n^r=C_{n+1}^{r+1} Crr+Cr+1r+Cr+2r+...+Cnr=Cn+1r+1

    C m e C n 0 + C m r − 1 C n 1 + . . . + C m 0 C n r = C n + m r C_m^eC_n^0+C_m^{r-1}C_n^1+...+C_m^0C_n^r=C_{n+_m}^r CmeCn0+Cmr1Cn1+...+Cm0Cnr=Cn+mr

    C n 0 + C n 1 + C n 2 + . . . + C n n = 2 n C_n^0+C_n^1+C_n^2+...+C_n^n=2^n Cn0+Cn1+Cn2+...+Cnn=2n

    C n 1 + C n 3 + C n 5 + . . . = C n 0 + C n 2 + C n 4 + . . . = 2 n − 1 C_n^1+C_n^3+C_n^5+...=C_n^0+C_n^2+C_n^4+...=2^{n-1} Cn1+Cn3+Cn5+...=Cn0+Cn2+Cn4+...=2n1

    ( C n 0 ) 2 + ( C n 1 1 ) 2 + . . . + ( C n n ) 2 = C 2 n n (C_n^0)^2+(C_n^11)^2+...+(C_n^n)^2=C_{2n}^n (Cn0)2+(Cn11)2+...+(Cnn)2=C2nn

    1 C n 1 + 2 C n 2 + 3 C n 3 + . . . + n C n n = n 2 n − 1 1C_n^1+2C_n^2+3C_n^3+...+nC_n^n=n2^{n-1} 1Cn1+2Cn2+3Cn3+...+nCnn=n2n1

    1 2 C n 1 + 2 2 C n 2 + 3 2 C n 3 + . . . + n 2 C n n = n ( n + 1 ) 2 n − 2 1^2C_n^1+2^2C_n^2+3^2C_n^3+...+n^2C_n^n=n(n+1)2^{n-2} 12Cn1+22Cn2+32Cn3+...+n2Cnn=n(n+1)2n2

    C n 1 1 − C − n 2 2 + C n 3 3 + . . . + ( − 1 ) n − 1 C n n n = 1 + 1 2 + 1 3 + . . . + 1 n \frac{C_n^1}{1}-\frac{C-n^2}{2}+\frac{C_n^3}{3}+...+(-1)^{n-1}\frac{C_n^n}{n}=1+\frac{1}{2}+\frac{1}{3}+...+\frac{1}{n} 1Cn12Cn2+3Cn3+...+(1)n1nCnn=1+21+31+...+n1

    ( C n 0 ) 2 + ( C n 1 ) 2 + ( C n 2 ) 2 + . . . + ( C n n ) 2 = C 2 n n (C_n^0)^2+(C_n^1)^2+(C_n^2)^2+...+(C_n^n)^2=C_{2n}^n (Cn0)2+(Cn1)2+(Cn2)2+...+(Cnn)2=C2nn

    在不全相异的n个物体中,假设有n1个物体是相同的,n2个物体是相同的,……,nk个物体是相同的。 n = ∑ i = 1 k n i n=\sum\limits_{i=1}^{k}n_i n=i=1kni那么,这些物体的全排列数是 n ! n 1 ! n 2 ! . . . n k ! \frac{n!}{n_1!n_2!...n_k!} n1!n2!...nk!n!

最长公共子序列

int dp[maxn][maxn][2], f[maxn][maxn];

int main()
{
    string aa, bb;
    cin >> aa >> bb;
    memset(dp, 0, sizeof(dp));
    memset(f, 0, sizeof(f));
    for (int i = 1; i <= aa.size(); i ++) {
        for (int j = 1; j <= bb.size(); j ++) {
            if(aa[i - 1] == bb[j - 1]) f[i][j] = f[i - 1][j - 1] + 1;
            else f[i][j] = 0;
        }
    }
    for (int i = 1; i <= aa.size(); i ++) {
        for (int j = 1; j <= bb.size(); j ++) {
            if(f[i][j] >= 3) {
                dp[i][j][1] = max(dp[i][j][1], dp[i - 3][j - 3][0] + 3);
                if(f[i][j] > 3) dp[i][j][1] = max(dp[i][j][1], dp[i - 1][j - 1][1] + 1);
            }
            dp[i][j][0] = max(max(dp[i - 1][j][0], dp[i][j - 1][0]), dp[i][j][1]);
        }
    }
    cout << dp[aa.size()][bb.size()][0] << endl;
    return 0;
}


高斯消元

#include 

using namespace std;
#define LL long long
const int Mod = 1e9 + 7;
const int maxn = 1e3 + 5;
const double eps = 0.0000001;
const int INF = 0x3f3f3f3f;

int n, m;
double a[maxn][maxn], x[maxn];
bool manySolutionFlag = false, noSolution = false;

void Swap(int i, int j) {
    for (int k = 1; k <= n + 1; k ++)
        swap(a[i][k], a[j][k]);
}

bool Check(int i) {
    bool vis = false;
    for (int j = 1; j <= n; j ++) {
        if(fabs(a[i][j]) >= eps) vis = true;
    }
    if(!vis && fabs(a[i][n + 1]) >= eps) return false;
    return true;
}

void GS() {
    for (int i = 1; i <= n; i ++) {
        bool flag = false;
        for (int j = i; j <= m; j ++) {
            if(a[j][i] != 0) {
                Swap(j, i);
                flag = true;
                break;
            }
        }
        if(!flag) {
            manySolutionFlag = true;
        }
        for (int j = i + 1; j <= m; j ++)
            for (int k = n + 1; k >= i; k --)
                a[j][k] = a[j][k] * 1. - a[i][k] * (a[j][i] * 1./a[i][i] * 1.) * 1.;

    }
    for (int i = 1; i <= m; i ++) {
        if(!Check(i)) {
            noSolution = true;
            return ;
        }
    }
    for (int i = n; i >= 1; i --) {
        for (int j = i + 1; j <= n; j ++) {
            a[i][n + 1] = a[i][n + 1] - a[i][j] * x[j];
            a[i][j] = 0;
        }
        x[i] = a[i][n + 1] * 1./a[i][i] * 1.;
    }
}

int main()
{
    cin >> n >> m;
    for (int i = 1; i <= m; i ++)
        for (int j = 1; j <= n + 1; j ++)
            cin >> a[i][j];
    GS();
    if(noSolution) cout << "No solutions" << endl;
    else if(manySolutionFlag) cout << "Many solutions" << endl;
    else {
        for (int i = 1; i <= n; i ++)
            cout << (int)(x[i] +0.5) << endl;
    }
    return 0;
}


SG函数

int SG[maxn], S[maxn];
int f[maxn];

void ff() {
    f[0] = 1;
    for (int i = 1; i <= 10; i ++)
        f[i] = f[i-1] * 2;
}

void getSG(int n) {
    ff();
    for (int i = 1; i <= n; i ++) {
        memset(S, 0, sizeof(S));
        for (int j = 0; f[j] <= i && j <= 10; j ++) 
            S[SG[i-f[j]]] = 1;
        for (int j = 0; ; j ++) 
            if(!S[j]) {
                SG[i] = j;
                break;
            }
    }
}

int main() { 
    int n;
    getSG(1000);
    while(cin >> n) {
        if(SG[n]) cout << "Kiki\n";
        else cout << "Cici\n";
    }   
    return 0;
}

三分求极值

double Com(double X) {
    return sqrt((X - x) * (X - x) + (a * X * X + b * X + c - y) * (a * X * X + b * X + c - y));
}

void Binary(double l, double r) {
    if(l + eps <= r) {
        double lm, rm;
        double k = r - l;
        lm = l + (1./3) * k;
        rm = r - (1./3) * k;
        if(fabs(Com(lm) - Com(rm)) <= eps) {
             printf("%.3lf\n", Com(lm));
             return ;
        }
        if(Com(lm) < Com(rm))
            Binary(l, rm);
        else Binary(lm, r);
    }
}

轮廓线dp

int dp[2][1<<5];
int n, m, cur;

void updata(int a, int b) {
    if(b & (1<<m)) dp[cur][b^(1<<m)] = dp[cur][b^(1<<m)] + dp[1-cur][a];
}

int main(int argc, char const *argv[]) {
    whhile(scanf("%d %d", &n, &m) != EOF && (n || m)) {
	    if(m > n) swap(n, m);
	    memset(dp, 0, sizeof(dp));
	    cur = 0;
	    dp[cur][(1<<m)-1] = 1;
	    for (int i = 0; i < n; i ++) {
	        for (int j = 0; j < m; j ++) {
	            cur ^= 1;
	            memset(dp[cur], 0, sizeof(dp[cur]));
	            for (int k = 0; k < (1<<m); k ++) {
	                updata(k, k<<1);
	                if(i && !(k & (1<<(m-1)))) updata(k, (k<<1)^(1<<m)^1);
	                if(j && (!(k & 1))) updata(k, (k<<1) ^ 3);
	            }
	        }
	    }
	    printf("%d", dp[cur][(1<<m)-1]);
    }
    return 0;
}

最长回文串

string LongestPalindrome(string s) {
    string newStr = "$#";
    for (int i = 0; i < s.size(); i ++) {
        newStr += s[i];
        newStr += '#';
    }
    vector<int> Len(newStr.size(), 0);
    int pos = 0, mx = 0;
    int sta = 0, maxLen = 0;
    for (int i = 1; i < newStr.size(); i ++) {
        Len[i] = i < mx ? min(Len[2*pos - i], mx - i) : 1;
        while(i + Len[i] < newStr.size() && i - Len[i] > 0 && newStr[i + Len[i]] == newStr[i - Len[i]])
            Len[i] ++;
        if(i + Len[i] > mx) {
            pos = i;
            mx = i + Len[i];
        }
        if(Len[i] - 1 > maxLen) {
            sta = (i - Len[i])/2;
            maxLen = Len[i] - 1;
        }
    }
    return s.substr(sta, maxLen);


数位dp

LL dfs(LL pos, LL m, LL status, bool limit) {
    if(!pos) return status == 2 && m == 0;//如果pos(位数)为0,即最后一位,并且前面对13取模的值为0
    if(!limit && dp[pos][m][status]) return dp[pos][m][status];//这时前面的所有位数遍历完,并且dp[pos][m][status]有值,即搜索过,直接输出
    LL end = limit ? num[pos] : 9;//上界,limit 表示前面的数都是极限值
    LL sum = 0;
    for (LL i = 0; i <= end; i ++) {
        LL a = m;
        LL flag = status;
        if(flag == 0 && i == 1) flag = 1;
        if(flag == 1 && i == 3) flag = 2;
        if(flag == 1 && i != 1 && i != 3) flag = 0;
        sum += dfs(pos - 1, (a * 10 + i) % 13, flag, limit && i == end);
    }
    return limit ? sum : dp[pos][m][status] = sum;
}

LL solve(LL n) {
    num[0] = 0;
    memset(dp, 0, sizeof(dp));
    while(n) {
        num[++ num[0]] = n % 10;
        n /= 10;
    }
    return dfs(num[0], 0, 0, 1);
}

最长上升子序列(LIS)

//O(nlogn)
b[1] = h[0];
len = 1;
for (int i = 1; i < cnt; i ++) {
    if(h[i] >= b[len]) b[++len] = h[i];
    else {
        int pos = upper_bound(b+1, b+1+len, h[i] - b;
        b[pos] = h[i];
    }
}
printf("%d\n", len);

容斥

一个简单的排列问题

由0到9的数字组成排列,要求第一个数大于1,最后一个数小于8,一共有多少种排列?
我们可以来计算它的逆问题,即第一个元素<=1或者最后一个元素>=8的情况。
∣ X ∣ + ∣ Y ∣ − ∣ X ∩ Y ∣ |X|+|Y|-|X\cap Y| X+YXY
我们设第一个元素<=1时有X组排列,最后一个元素>=8时有Y组排列。那么通过容斥原理来解决就可以写成:
2 ⋅ 9 ! + 2 ⋅ 9 ! − 4 ⋅ 8 ! 2\cdot9!+2\cdot9!-4\cdot 8! 29!+29!48!

(0,1,2)序列问题

长度为n的由数字0,1,2组成的序列,要求每个数字至少出现1次,这样的序列有多少种?
同样的,我们转向它的逆问题。也就是不出现这些数字的序列 不出现其中某些数字的序列。
我们定义Ai(i=0…2)表示不出现数字i的序列数,那么由容斥原理,我们得到该逆问题的结果为:
∣ A 1 ∣ + ∣ A 2 ∣ + ∣ A 3 ∣ − ∣ A 1 ∩ A 2 ∣ − ∣ A 2 ∩ A 3 ∣ − ∣ A 1 ∩ A 3 ∣ + ∣ A 1 ∩ A 2 ∩ A 3 ∣ |A_1|+|A_2|+|A_3|-|A_1\cap A_2|-|A_2\cap A_3|-|A_1 \cap A_3|+|A_1\cap A_2\cap A_3| A1+A2+A3A1A2A2A3A1A3+A1A2A3

可以发现每个Ai的值都为2^n(因为这些序列中只能包含两种数字)。而所有的两两组合都为1(它们只包含1种数字)。最后,三个集合的交集为0。(因为它不包含数字,所以不存在)
要记得我们解决的是它的逆问题,所以要用总数减掉,得到最终结果:
3 n − 3 ⋅ 2 n + 3 ⋅ 1 − 0 3^n-3\cdot 2^n + 3\cdot 1 - 0 3n32n+310

方程整数解问题

给出一个方程:
X 1 + X 2 + X 3 + X 4 + X 5 + X 6 = 20 X_1+X_2+X_3+X_4+X_5+X_6=20 X1+X2+X3+X4+X5+X6=20 其中。 X i < = 8 X_i<=8 Xi<=8
求这个方程的整数解有多少组。

我们先不去理会 X i ≤ 8 X_i\leq8 Xi8的条件,来考虑所有正整数解的情况。这个很容易用组合数来求解,我们要把20个元素分成6组,也就是添加5块“夹板”,然后在25个位置中找5块“夹板”的位置。 N 0 = C 25 5 N_0=C_{25}^5 N0=C255
然后通过容斥原理来讨论它的逆问题,也就是 X ≥ 9 X\geq9 X9时的解。
我们定义Ak为 X k ≥ 9 X_k\geq 9 Xk9并且其他 X i ≥ 0 X_i\geq0 Xi0时的集合,同样我们用上面的添加“夹板”法来计算 A k A_k Ak的大小,因为有9个位置已经被 X k X_k Xk所利用了,所以: ∣ A k ∣ = C 16 5 |A_k| = C_{16}^5 Ak=C165
然后计算两个这样的集合 A k 、 A p A_k、A_p AkAp的交集: ∣ A k ∩ A p ∣ = C 7 5 |A_k\cap A_p|=C_7^5 AkAp=C75
因为所有x的和不能超过20,所以三个或三个以上这样的集合时是不能同时出现的,它们的交集都为0。最后我们用总数剪掉用容斥原理所求逆问题的答案,就得到了最终结果:
C 25 5 − C 6 1 ⋅ C 16 5 + C 6 2 ⋅ C 7 5 C_{25}^5-C_6^1\cdot C_{16}^5+C_6^2\cdot C_7^5 C255C61C165+C62C75

其他

在[1,n]中与n互质的数的和

∑ i = 1 n i [ g c d ( i , n ) = = 1 ] \sum\limits_{i=1}^{n}i[gcd(i,n)==1] i=1ni[gcd(i,n)==1]
在[1,n]中与n互质的数的和为 φ ( n ) ⋅ n + [ n = = 1 ] 2 \frac{\varphi(n)\cdot n+[n==1]}{2} 2φ(n)n+[n==1]

a,b不能组成的最大数字是 a ∗ b − a − b a*b-a-b abab

勾三股四弦五

a 2 + b 2 = c 2 , 根 据 勾 三 股 四 弦 五 a^2 +b^2=c^2,根据勾三股四弦五 a2+b2=c2,
当勾为奇数是:
a = 2 n + 1 , b = 2 n 2 + 2 n , c = b + 1 a=2n+1, b=2n^2+2n,c=b+1 a=2n+1,b=2n2+2n,c=b+1
当勾为偶数是:
a = 2 n + 2 , b = n 2 + 2 n , c = b + 2 a=2n+2,b=n^2+2n,c=b+2 a=2n+2,b=n2+2n,c=b+2

__int128_t的使用

 using namespace std;
 inline __int128 read(){
     __int128 x=0,f=1;
     char ch=getchar();
     while(ch<'0'||ch>'9'){
         if(ch=='-')
             f=-1;
         ch=getchar();
     }
     while(ch>='0'&&ch<='9'){
         x=x*10+ch-'0';
         ch=getchar();
     }
     return x*f;
 }
 
 inline void print(__int128 x){
     if(x<0){
         putchar('-');
         x=-x;
     }
     if(x>9)
         print(x/10);
     putchar(x%10+'0');
 }
 
 int main(void){
     __int128 a = read();
     __int128 b = read();
     print(a + b);
     cout<<endl;
     return 0;
 }

卡特兰数

前几项: 1, 1, 2, 5, 14, 42, 132, 429, 1430, 4862, 16796, 58786, 208012, 742900, 2674440, 9694845, 35357670, 129644790, 477638700, 1767263190, 6564120420, 24466267020, 91482563640, 343059613650, 1289904147324, 4861946401452, ...

递推式: f [ i ] = f [ i − 1 ] ⋅ 4 i − 2 i + 1 f[i] = f[i-1]\cdot \frac{4i-2}{i+1} f[i]=f[i1]i+14i2

del 删除exe

del /s /q *.exe

你可能感兴趣的:(模版)