终于想起要填一个坑了! 数论(杂七杂八滴)水题专栏
??? 子集和的异或和
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,p为素数⇒gcd(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
,使,即有
φ(1)+φ(2)+...+φ(⌊np⌋)
φ
(
1
)
+
φ
(
2
)
+
.
.
.
+
φ
(
⌊
n
p
⌋
)
对,求
phi
p
h
i
前缀和实现,
a、b
a
、
b
可以互换要
∗2−1(gcd(1,1)
∗
2
−
1
(
g
c
d
(
1
,
1
)
每次都多算了一次
)
)
然后枚举以内所有素数即可。
#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;
}
扩展欧拉函数
ab≡ab%φ(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
继续努力。