数论!

终于想起要填一个坑了! 数论(杂七杂八滴)水题专栏

??? 子集和的异或和

bitset中第i位表示子集和为i的情况个数的奇偶性(偶数个对结果没有贡献

#include<iostream>
#include<cstdio>
#include<bitset>
using namespace std;

int a;
bitset < 2000000 > b;

int main ( ) {
    int n;
    scanf ( "%d", &n );
    b[0] = 1;
    for ( int i = 1; i <= n; i ++ ) {
        scanf ( "%d", &a );
        b ^= b << a;
    }
    int ans = 0; 
    for ( int i = 1; i <= 2000000; i ++ )
        if ( b[i] ) ans ^= i;
    printf ( "%d", ans );
    return 0;
}

康拓展开及逆

不开long long死的真的很惨…

#include<iostream>
#include<cstdio>
using namespace std;

int a[25];
long long n, m;
long long fac[25];

void init ( ) {
    fac[0] = 1;
    for ( int i = 1; i <= 24; i ++ )
        fac[i] = fac[i-1] * i;
}

long long kangtuo ( ) {
    long long ans = 0;
    for ( int i = 0; i < n; i ++ ) {
        long long t = 0;
        for ( int j = i+1; j < n; j ++ ) {
            if ( a[i] > a[j] ) t ++;
        }
        ans += 1LL*fac[n-i-1]*t;
    }
    return ans+1;
}

int vis[25];

void rev_kangtuo( )  
{  
    int i, j, vst[100]={0};
    long long t;  
    --m;  
    for (i=0; i<n; i++)  
    {  
        t = m/fac[n-i-1];  
        for (j=1; j<=n; j++)  
            if (!vst[j])  
            {  
                if (t == 0) break;  
                --t;
            }  
        vst[j] = 1;
        printf ( "%d ", j );
        m %= fac[n-i-1];  
    }  
}  

int main ( ) {
    scanf ( "%d%lld", &n, &m );
    init ( );
    for ( int i = 0; i < n; i ++ )
        scanf ( "%d", &a[i] );
    long long ans = kangtuo ( );
    printf ( "%lld", ans );
    printf ( "\n" );
    rev_kangtuo ( );
    return 0;
}

欧拉函数!!

真的是太博大精深了…

get_phi

void get_phi1 ( ) {
    isnot[1] = 1;
    for ( int i = 2; i <= n; i ++ ) {
        if ( !isnot[i] ) prime[++tot] = i;
        for ( int j = 1; j <= tot; j ++ ) {
            if ( prime[j] * i > n ) break;
            isnot[i*prime[j]] = 1;
            if ( i % prime[j] == 0 ) break;
        }
    }

    for ( int i = 1; i <= n; i ++ ) phi[i] = i;
    for ( int i = 1; i <= tot; i ++ )
        for ( int j = prime[i]; j <= n; j += prime[i] ) {
            phi[j] /= prime[i];
            phi[j] *= ( prime[i]-1 );
        }
}



void get_phi2 ( ) {
    isnot[1] = 1;
    for ( int i = 2; i <= n; i ++ ) {
        if ( !isnot[i] ) prime[++tot] = i;
        for ( int j = 1; j <= tot; j ++ ) {
            if ( prime[j] * i > n ) break;
            isnot[i*prime[j]] = 1;
            if ( i % prime[j] == 0 ) {
                phi[i*prime[j]] = prime[j] * phi[i];
                break;
            } else phi[i*prime[j]] = phi[prime[j]] * phi[i];
        }
    }
}

bzoj2818

gcd(a,b)=p,pgcd(ap,bp)=1 g c d ( a , b ) = p , p 为 素 数 ⇒ g c d ( a p , b p ) = 1

我们设 ap<bp a p < b p ,那么能使上式成立有 φ(bp) φ ( b p )
对于一个 p p ,使gcd(a,p)(=p)+gcd(a,2p)(=p)+...gcd(a,kp)(=p),(kp<=n),即有 φ(1)+φ(2)+...+φ(np) φ ( 1 ) + φ ( 2 ) + . . . + φ ( ⌊ n p ⌋ ) 对,求 phi p h i 前缀和实现, ab a 、 b 可以互换要 21(gcd(1,1) ∗ 2 − 1 ( g c d ( 1 , 1 ) 每次都多算了一次 ) ) 然后枚举n以内所有素数即可。

#include<iostream>
#include<cstdio>
#define ll long long
using namespace std;

int n;

const int N = 1e7+1;

ll phi[N];
int prime[2000005], tot;
bool isnot[N];

void init ( ) {
    isnot[1] = 1;
    for ( int i = 2; i <= n; i ++ ) {
        if ( !isnot[i] ) prime[++tot] = i;
        for ( int j = 1; j <= tot; j ++ ) {
            if ( prime[j] * i > n ) break;
            isnot[i*prime[j]] = 1;
            if ( i % prime[j] == 0 ) break;
        }
    }

    for ( int i = 1; i <= n; i ++ ) phi[i] = i;
    for ( int i = 1; i <= tot; i ++ )
        for ( int j = prime[i]; j <= n; j += prime[i] ) {
            phi[j] /= prime[i];
            phi[j] *= ( prime[i]-1 );
        }
    for ( int i = 2; i <= n; i ++ ) phi[i] += phi[i-1]; ///计算phi的前缀和
}

int main ( ) {
    scanf ( "%d", &n );
    init ( );
    ll ans = 0;
    for ( int i = 1; i <= tot && prime[i] <= n; i ++ ) 
        ans += (ll) ( 2 * phi[n/prime[i]] - 1 );
    printf ( "%lld", ans );
    return 0;
}

扩展欧拉函数

abab%φ(p)+φ(p) (mod p), b>=φ(p) a b ≡ a b % φ ( p ) + φ ( p )   ( m o d   p ) ,   b >= φ ( p )

bzoj 3884
#include<iostream>
#include<cstdio>
using namespace std;

int phi ( int x ) {
    int an = x;
    for ( int i = 2; i * i <= x; i ++ ) {
        if ( x % i == 0 ) {
            an -= an / i;
            while ( x % i == 0 )
                x /= i;
        }
    }
    if ( x > 1 ) an -= an / x;
    return an;
}

int mpow ( int a, int b, int p ) {
    int an = 1;
    for ( ; b; b >>= 1, a = 1ll * a * a % p )
        if ( b & 1 ) an = 1ll * an * a % p;
    return an;
}

int get ( int x ) {
    if ( x == 1 ) return 0;
    int pi = phi ( x );
    return mpow ( 2, get ( pi ) + pi, x );
}

int main ( ) {
    int T;
    scanf ( "%d", &T );
    while ( T -- ) {
        int p;
        scanf ( "%d", &p );
        printf ( "%d\n", get ( p ) );
    }
    return 0;
}

LUCAS

(nm)(npmp)(n%pm%p)(mod p) ( n m ) ≡ ( n p m p ) ∗ ( n % p m % p ) ( m o d   p )

#include<iostream>
#include<cstdio>
using namespace std;
#define ll long long
#define mod 9901

ll vfac[10005], fac[10005];

ll mi ( ll a, ll b ) {
    ll an = 1;
    for ( ; b; b >>= 1, a = a * a % mod )
        if ( b & 1 ) an = an * a % mod;
    return an;
}

ll rev ( ll a ) {
    return mi ( a, mod-2 );
}

void init ( ) {
    fac[0] = 1, vfac[0] = 1;
    for ( int i = 1; i <= 10000; i ++ ) {
        fac[i] = fac[i-1] * i % mod;
        vfac[i] = rev ( fac[i] );
    }
}

ll comb ( int i, int j ) {
    if ( i < j ) return 0;
    return fac[i] * vfac[j] % mod * vfac[i-j] % mod;
}

ll Lucas ( int i, int j ) {
    if ( i < j ) return 0;
    if ( i == 0 && j == 0 ) return 1;
    return Lucas ( i/mod, j/mod ) * comb(i%mod,j%mod) % mod;
}

int main ( ) {
    int m, n;
    init ( );
    scanf ( "%d%d", &m, &n );
    ll ans = Lucas ( m, n );
    printf ( "%lld", ans );
    return 0;
}

容斥原理

scoi 2010 幸运数字
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long

ll x, y;
ll qaq[3005],qwq[3005], ans, nu, sum;

ll gcd ( ll a, ll b ) {
    if ( b == 0 ) return a;
    return gcd ( b, a%b );
}

void init ( ll a, ll b ) {
    if ( b > y ) return ;
    if ( a > 0 ) qaq[++nu] = b;
    init ( a+1, b*10+6 );
    init ( a+1, b*10+8 );
}

void dfs ( ll now, ll aa, ll bb ) {
    if ( bb > y ) return ;
    if ( now > sum ) {
        if ( aa == 0 ) return ;
        if ( aa & 1 ) ans += y/bb - (x-1)/bb;
        else if ( aa ) ans -= y/bb - (x-1)/bb;
        return ;
    }
    dfs ( now+1, aa, bb );
    ll tmp = bb/gcd ( qaq[now], bb );
    if ( (double)qaq[now] * tmp <= y )
        dfs ( now+1, aa+1, qaq[now]*tmp );
}

int vis[3005];

int main ( ) {
    scanf ( "%lld%lld", &x, &y );
    init ( 0, 0 );
    sort ( qaq+1, qaq+nu+1 );
    for ( int i = 1; i <= nu; i ++ ) {
        if ( vis[i] ) continue;
        qwq[++sum] = qaq[i];
        for ( int j = i+1; j <= nu; j ++ )
            if ( qaq[j] % qaq[i] == 0 )
                vis[j] = 1;
    }
    for ( int i = 1; i <= sum; i ++ )
        qaq[sum-i+1] = qwq[i];
    dfs ( 1, 0, 1 );
    printf ( "%lld", ans );
    return 0;
}

模拟退火

吊打xxx
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;

int n;

struct node {
    double x, y, w;
} zb[1006], an, now;

double count ( double x, double y ) {
    double an = 0;
    for ( int i = 1; i <= n; i ++ ) {
        double nowx = x - zb[i].x;
        double nowy = y - zb[i].y;
        an += ( sqrt ( nowx * nowx + nowy * nowy ) ) * zb[i].w;
    }
    return an;
}

double ans;

void SA ( ) {
    double T = 99588;
    while ( T > 1e-15 ) {
        double xx = now.x + ( rand ( ) * 2 - RAND_MAX ) * T;
        double yy = now.y + ( rand ( ) * 2 - RAND_MAX ) * T;
        double now_ans = count ( xx, yy );
        double DE = now_ans - ans;
        if ( DE < 0 ) {
            now.x = xx;
            now.y = yy;
            ans = now_ans;  
        } 
        else if ( exp ( -DE / T ) * RAND_MAX > rand ( ) ) {
                now.x = xx; 
                now.y = yy;
                ans = now_ans;
            }
        T *= 0.998;
    }
}

int main ( ) {
    scanf ( "%d", &n );
    an.x = an.y = an.w = 0; 
    for ( int i = 1; i <= n; i ++ ) {
        scanf ( "%lf%lf%lf", &zb[i].x, &zb[i].y, &zb[i].w );
        an.x += zb[i].x, an.y += zb[i].y;
    }
    an.x /= n; an.y /= n;
    ans = count ( an.x, an.y );
    now = an;
    for ( int i = 1; i <= 3; i ++ ) SA ( );
    printf ( "%0.3lf %0.3lf", now.x, now.y );
    return 0;
}

排列组合

poj1715

枚举每一位,从大到小填数,通过所有排列数判断是否可行

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;

int jc[20];

char num[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
char ans[16];
int vis[16], flag;

int pl ( int n, int m )
{
    int res = 1;
    if( m == 0 ) return 1;
    while( m -- ) {
        res *= n;
        n --;
    }
    return res;
}

void solut ( int n ) {
    memset ( vis, 0, sizeof ( vis ) );
    int QWQ; flag = 0; int use = 0;
    for ( int i = 1; i <= 8; i ++ ) {
        int j = 15;
        while ( j ) {
            if ( !vis[j] ) {
                QWQ = pl ( 15-use, 8-i );
                if ( QWQ < n ) n -= QWQ;
                else {
                    vis[j] = 1;
                    break;
                }
            }
            j --;
        }
        ans[i] = num[j];
        if ( ans[i] != '0' ) flag = 1;
        if ( flag || ans[i] != '0' ) use ++;
    }
}

int main ( ) {
    int n;
    while ( scanf ( "%d", &n ) == 1 ) {
        solut ( n );
        flag = 0;
        for ( int i = 1; i <= 8; i ++ ) {
            if ( flag || ans[i] != '0' ) {
                printf ( "%c", ans[i] ); flag = 1;
            }
        }
        if ( !flag ) printf ( "0" );
        printf ( "\n" );
    }
    return 0;
}

好像还有很多没贴,,公式太难打了,以后补充吧qwq

继续努力。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值