数学
图论
DP
其他
欧几里得
typedef long long LL ;
LL gcd(LL a,LL b)
{
return b==0 ? a :gcd(b,a%b);
}
扩欧几里得
inline LL exgcd(LL a,LL b,LL &x,LL &y){
if(b == 0){
x = 1,y = 0;
return a;
}
LL g = exgcd(b,a%b,x,y);
LL tep = x;
x = y;
y = tep-a/b*y;
return g;
}
类欧几里得
求 ∑ x = 1 n ⌊ C + B x A ⌋ \sum_{x=1}^n\left\lfloor\frac{C+Bx}{A}\right\rfloor ∑x=1n⌊AC+Bx⌋
#define LL __int128
long long Sum(LL n,LL a,LL b,LL c)
{
if(n<=0) return 0;
LL ans=0;
if(c<0)
{
LL t=(a-c-1)/a;
c+=a*t;
ans-=n*t;
}
if(b<0)
{
LL t=(a-1-b)/a;
b+=a*t;
ans-=(n+1)*n*t/2;
}
if(c/a>0||b/a>0)
{
ans+=(c/a)*n;ans+=(b/a)*n*(n+1)/2;
c%=a;b%=a;
}
LL newn=(b*n+c)/a;
ans+=newn*(n+1)-Sum(newn,b,a,-c+b-1);
return ans;
}
#undef LL
求 ∑ i = 1 n ⌊ a i + b c ⌋ ( m o d m o d ) \sum_{i=1}^n\left\lfloor\frac{ai+b}{c}\right\rfloor(mod\ mod) ∑i=1n⌊cai+b⌋(mod mod)(即有模数)
ll Sum(ll a,ll b,ll c,ll n){
if (!a) return 0;
ll x,y;
if(a>=c||b>=c){
x=Sum(a%c,b%c,c,n);
y=((a/c)%mod*(n%mod)%mod*((n+1)%mod)%mod*inv2+b/c%mod*((n+1)%mod)+x)%mod;
y=(y+mod)%mod;
return y;
}
ll m=((__int128)a*n+b)/c;
x=Sum(c,c-b-1,a,m-1);
y=((__int128)n*m-x)%mod;
y=(y+mod)%mod;
return y;
}
复杂度 O ( n 1 4 ) O(n^{1\over 4}) O(n41)大约可以分解1e18一百次
#include
#include
#include
#include
using namespace std;
typedef long long LL;
long long factor[110], cnt;
long long Mul_Mod(long long a, long long b, long long c) {
if (b == 0)
return 0;
long long ans = Mul_Mod(a, b / 2, c);
ans = (ans * 2) % c;
if (b % 2)
ans = (ans + a) % c;
return ans;
}
long long Pow_Mod(long long a, long long b, long long c) {
if (b == 0)
return 1;
long long x = Pow_Mod(a, b / 2, c);
if (x == 0)
return 0;
long long y = Mul_Mod(x, x, c);
if (y == 1 && x != 1 && x != c - 1)
return 0;
if (b % 2)
y = Mul_Mod(y, a, c);
return y;
}
bool Miller_rabin(long long n, int timenum = 10) {
if (n < 2)
return false;
if (n == 2)
return true;
while (timenum--) {
if (Pow_Mod(rand() % (n - 2) + 2, n - 1, n) != 1)
return false;
}
return true;
}
long long Gcd(long long a, long long b) {
long long t;
while (b) {
t = a;
a = b;
b = t % b;
}
return a;
}
void Pollard(long long n);
void Factor(long long n) {
long long d = 2;
while (true) {
if (n % d == 0) {
Pollard(d);
Pollard(n / d);
return;
}
d++;
}
}
void Pollard(long long n) {
if (n <= 0)
printf("error\n");
if (n == 1)
return;
if (Miller_rabin(n)) {
factor[cnt++] = n;
return;
}
long long i = 0, k = 2, x, y, d;
x = y = rand() % (n - 1) + 1;
while (i++ < 123456) {
x = (Mul_Mod(x, x, n) + n - 1) % n;
d = Gcd((y - x + n) % n, n);
if (d != 1) {
Pollard(d);
Pollard(n / d);
return;
}
if (i == k) {
y = x;
k *= 2;
}
}
Factor(n);
}
int main() {
int Case;
long long n;
scanf("%d", &Case);
while (Case--) {
scanf("%lld", &n);
if (Miller_rabin(n))
printf("Prime\n");
else {
cnt = 0;
Pollard(n);
sort(factor, factor + cnt);
for(int i=0;i<cnt;i++)
printf("%lld\n", factor[i]);
}
}
return 0;
}
扩欧求逆元
LL exgcd(LL a,LL b,LL &x,LL &y)//扩展欧几里得算法
{
if(b==0)
{
x=1,y=0;
return a;
}
LL ret=exgcd(b,a%b,y,x);
y-=a/b*x;
return ret;
}
LL getInv(int a,int mod)//求a在mod下的逆元,不存在逆元返回-1
{
LL x,y;
LL d=exgcd(a,mod,x,y);
return d==1?(x%mod+mod)%mod:-1;
}
递推求逆元
LL inv[mod+5];
void getInv(LL mod)
{
inv[1]=1;
for(int i=2;i<mod;i++)
inv[i]=(mod-mod/i)*inv[mod%i]%mod;
}
欧拉定理扩展:小于n与n互质的数的和为 ϕ ( n ) ∗ n / 2 \phi(n)*n/2 ϕ(n)∗n/2
欧拉函数的通项公式: ϕ ( x ) = x ∏ i = 1 n ( 1 − 1 p i ) \phi(x)=x\prod_{i=1}^n(1-\frac{1}{p_i}) ϕ(x)=x∏i=1n(1−pi1)其中p为x的质因数
log(n)求单个值
int oula(int 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;
}
素数筛
void euler(int n)
{
phi[1]=1;
for (int i=2;i<=n;i++)
{
if (flag[i]==0)
{
prime[++num]=i;
phi[i]=i-1;
}
for (int j=1;j<=num&&prime[j]*i<=n;j++)
{
flag[i*prime[j]]=1;
if (i%prime[j]==0)
{
phi[i*prime[j]]=phi[i]*prime[j];
break;
}
else phi[i*prime[j]]=phi[i]*phi[prime[j]];
}
}
}
CRT
void exgcd(int a,int b,int &x,int &y)
{
if(b==0){ x=1; y=0; return;}
exgcd(b,a%b,x,y);
int tp=x;
x=y; y=tp-a/b*y;
}
int china()
{
int ans=0,lcm=1,x,y;
for(int i=1;i<=k;++i) lcm*=b[i];
for(int i=1;i<=k;++i)
{
int tp=lcm/b[i];
exgcd(tp,b[i],x,y);
x=(x%b[i]+b[i])%b[i];//x要为最小非负整数解
ans=(ans+tp*x*a[i])%lcm;
}
return (ans+lcm)%lcm;
}
EXCRT
LL work(){
LL M=m[1],A=a[1],t,d,x,y;int i;
for(i=2;i<=n;i++){
d=exgcd(M,m[i],x,y);
if((a[i]-A)%d)return -1;
x*=(a[i]-A)/d,t=m[i]/d,x=(x%t+t)%t;
A=M*x+A,M=M/d*m[i],A%=M;
}
A=(A%M+M)%M;
return A;
}
// How to calculate x^k (mod p) =
#include
using namespace std;
typedef long long LL;
void extgcd(long long a,long long b,long long &x,long long &y)
{
if(b == 0) x = 1,y = 0;
else{
extgcd(b,a%b,y,x);
y -= a/b*x;
}
}
long long Phi(LL n)
{
long long ans = n;
for(int i = 2;i < n; ++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;
}
long long qpow(long long a,long long b,long long m){
long long ans = 1;
a %= m;
while(b>0){
if(b&1) ans = ans*a%m;
a = a*a%m;
b >>= 1;
}
return ans;
}
int main(void)
{
// init();
LL x,k,b,m;
LL xx,yy;
while(cin>>k>>b>>m){
long long Phim = Phi(m);
// cout<
extgcd(k,Phim,xx,yy);
xx = (xx%Phim+Phim)%Phim;
cout<<xx<<endl;
x = qpow(b,xx,m);
cout<<x<<endl;
cout<<qpow(x,k,m)<<endl;
}
return 0;
}
c++
// 18位素数:154590409516822759
// 19位素数:2305843009213693951 (梅森素数)
// 19位素数:4384957924686954497
LL prime[6] = {2, 3, 5, 233, 331};
LL qmul(LL x, LL y, LL mod) { // 乘法防止溢出, 如果p * p不爆LL的话可以直接乘; O(1)乘法或者转化成二进制加法
return (x * y - (long long)(x / (long double)mod * y + 1e-3) *mod + mod) % mod;
}
LL qpow(LL a, LL n, LL mod) {
LL ret = 1;
while(n) {
if(n & 1) ret = qmul(ret, a, mod);
a = qmul(a, a, mod);
n >>= 1;
}
return ret;
}
bool Miller_Rabin(LL p) {
if(p < 2) return 0;
if(p != 2 && p % 2 == 0) return 0;
LL s = p - 1;
while(! (s & 1)) s >>= 1;
for(int i = 0; i < 5; ++i) {
if(p == prime[i]) return 1;
LL t = s, m = qpow(prime[i], s, p);
while(t != p - 1 && m != 1 && m != p - 1) {
m = qmul(m, m, p);
t <<= 1;
}
if(m != p - 1 && !(t & 1)) return 0;
}
return 1;
}
python
import random
def QuickPow(a, b, MOD):
ret = 1
tmp = a%MOD
while b>0:
if (b&1):
ret = (ret*tmp)%MOD
tmp = (tmp*tmp)%MOD
b >>= 1
return ret
def Miller_Rabin(a, p): # a^(p-1) = 1 (mod p)
p1 = p-1
s2 = p1 & -p1 # fetch the last 1
x = QuickPow(a, p1//s2, p)
if x == 1 or x == p1:
return True
while s2>1:
x = (x*x)%p
if x == 1:
return False
if x == p1:
return True
s2 >>= 1
return False
def IsPrime(p, k):
if p == 2 or p == 3:
return True
if p < 2 or (p&1) == 0:
return False
for i in range(k):
if not Miller_Rabin(random.randint(2, p-1), p):
return False
return True
n = int(input())
for i in range(n):
p = int(input())
print('YES' if IsPrime(p, 5) else 'NO')
∑ i = 1 n ∑ j = 1 m [ g c d ( i , j ) = d ] = ∑ i = 1 n ∑ j = 1 m ∑ p ∣ g c d ( i d , j d ) μ ( p ) \sum_{i=1}^n\sum_{j=1}^m[gcd(i,j)=d]=\sum_{i=1}^n\sum_{j=1}^m\sum_{p|gcd(\frac{i}{d},\frac{j}{d})}\mu(p) i=1∑nj=1∑m[gcd(i,j)=d]=i=1∑nj=1∑mp∣gcd(di,dj)∑μ(p)
2.
莫比乌斯函数卷积单位函数为欧拉函数
3.
∑ i = 1 n g c d ( n , i ) = ∑ d ∣ n d φ ( n d ) \sum_{i=1}^{n}gcd(n,i)=\sum_{d|n}d\varphi({n\over d}) ∑i=1ngcd(n,i)=∑d∣ndφ(dn)
∑ i = 1 n ∑ j = 1 n i ⋅ j [ g c d ( i , j ) = 1 ] = ∑ i = 1 n i 2 φ ( i ) \sum_{i=1}^n\sum_{j=1}^ni\cdot j[gcd(i,j)=1]=\sum_{i=1}^ni^2\varphi(i) i=1∑nj=1∑ni⋅j[gcd(i,j)=1]=i=1∑ni2φ(i)
μ ∗ I = e \mu*I=e μ∗I=e
也就是说 I I I和 μ \mu μ互为逆元
φ ∗ I = i d \varphi*I=id φ∗I=id
同理也就有
φ = i d ∗ μ \varphi=id*\mu φ=id∗μ
根据这个式子可以推出另一个非常巧妙的公式
ϕ ( n ) n = ∑ d ∣ n μ ( d ) d \frac{\phi (n)}{n}=\sum_{d|n}\frac{\mu(d)}{d} nϕ(n)=d∣n∑dμ(d)
I ∗ i d = σ I*id=\sigma I∗id=σ
同理也就有
i d = σ ∗ μ id=\sigma*\mu id=σ∗μ
I ∗ I = d I*I=d I∗I=d
同理也就有
I = d ∗ μ I=d*\mu I=d∗μ
( i d ⋅ φ ) ∗ i d = i d 2 (id\cdot \varphi)*id=id^2 (id⋅φ)∗id=id2
∑ i = 1 a ∑ j = 1 b ∑ k = 1 c d ( i j k ) = ∑ g c d ( i , j , k ) = 1 ⌊ a i ⌋ ⌊ b j ⌋ ⌊ c k ⌋ \sum_{i=1}^a\sum_{j=1}^b\sum_{k=1}^cd(ijk)=\sum_{gcd(i,j,k)=1} \left\lfloor{a\over i}\right\rfloor\left\lfloor{b\over j}\right\rfloor\left\lfloor{c\over k}\right\rfloor i=1∑aj=1∑bk=1∑cd(ijk)=gcd(i,j,k)=1∑⌊ia⌋⌊jb⌋⌊kc⌋
小于等于n与n互素的数之和
∑ i = 1 n [ g c d ( i , n ) = 1 ] i = 1 2 ( [ n = 1 ] + n φ ( n ) ) \sum_{i=1}^n[gcd(i,n)=1]i=\frac{1}{2}([n=1]+n\varphi(n)) i=1∑n[gcd(i,n)=1]i=21([n=1]+nφ(n))
1-n中的数与n的gcd的和
∑ i = 1 n g c d ( i , n ) = ∑ d ∣ n d φ ( n d ) \sum_{i=1}^ngcd(i,n)=\sum_{d|n}d\varphi(\frac{n}{d}) i=1∑ngcd(i,n)=d∣n∑dφ(dn)
φ = φ ∗ μ ∗ I \varphi=\varphi*\mu*I φ=φ∗μ∗I
对于欧拉函数卷积莫比乌斯函数有递推式
if(i%Prime[j]==0)
{
if((i/Prime[j])%Prime[j]==0) muphi[i*Prime[j]]=muphi[i]*Prime[j];
else muphi[i*Prime[j]]=(Prime[j]-1)*(Prime[j]-1)*muphi[i/Prime[j]];
break;
}
else
{
muphi[i*Prime[j]]=muphi[i]*muphi[Prime[j]];
}
定义一个函数
c s l ( p , x ) = { 3 e + 1 x = p e a n d ∃ a , b p = a 2 + b 2 1 x = p e a n d ∄ a , b p = a 2 + b 2 0 o t h e r csl(p,x)=\begin{cases} 3e+1& x=p^e\ and\ \exist a,b\ p=a^2+b^2\\ 1& x=p^e\ and\ \not\exist a,b\ p=a^2+b^2\\ 0 & other \end{cases} csl(p,x)=⎩⎪⎨⎪⎧3e+110x=pe and ∃a,b p=a2+b2x=pe and ∃a,b p=a2+b2other
再定义 t l ( p , x ) = m a x d ∣ x ( c s l ( p , d ) ) tl(p,x)=max_{d|x}(csl(p,d)) tl(p,x)=maxd∣x(csl(p,d))现在要求求
∑ d = 1 n ∏ p t l ( p , d ) \sum_{d=1}^n\prod_ptl(p,d) d=1∑np∏tl(p,d)
#include
using namespace std;
#define int long long
typedef long long LL;
int s,n;
const int size=1e5+5;
int pre[size][4],p[size];
bool prime[size];
int tot;
int num[size];
int h[size][4];
int tol;
inline int ID(LL x){return x<=s?x:tol-n/x+1;}//x should be LL
inline int f(int p,int e)
{
if(p%4==1) return 3*e+1;
return 1;
}
LL get_g(int x,int k)
{
if(x<=1||p[k]>x) return 0;
LL ans=h[ID(x)][3]-pre[k-1][3]+(h[ID(x)][1]-pre[k-1][1])*4;
if(k==1) ans++;//'2' is specil
while(1LL*p[k]*p[k]<=x&&k<=tot)
{
int pk=p[k],t=p[k];
for(int e=1;t*pk<=x;e++,t=t*pk)
ans=ans+f(pk,e)*(get_g(x/t,k+1))+f(pk,e+1);
k++;
}
return ans;
}
void get_h(int n)
{
s=sqrt(n);
tot=0;
while(s*s<=n) s++;
while(s*s>n) s--;
for(int j=0;j<4;j++) pre[0][j]=0;
for(int i=1;i<=s;i++) prime[i]=true;
for(int i=2;i<=s;i++)
{
if(prime[i])
{
p[++tot]=i;
for(int j=0;j<4;j++) pre[tot][j]=pre[tot-1][j]+(i%4==j);
}
for(int j=1;j<=tot&&p[j]*i<=s;j++)
{
prime[i*p[j]]=false;
if(i%p[j]==0) break;
}
}
tol=0;
for(int i=1;i<=s;i++) num[++tol]=i;
for(int i=s;i>=1;i--) if(n/i>s) num[++tol]=n/i;
for(int i=1;i<=tol;i++)
{
h[i][1]=num[i]/4+(num[i]%4>=1)-1;
h[i][3]=num[i]/4+(num[i]%4>=3);
h[i][2]=num[i]/4+(num[i]%4>=2);
h[i][0]=num[i]/4;
}
int x=1;
for(int j=1;j<=tot;j++)
{
while(num[x]<p[j]*p[j]) x++;
for(int i=tol;i>=x;i--)
{
for(int r=0;r<4;r++)
{
h[i][r*p[j]%4]=h[i][r*p[j]%4]-(h[ID(num[i]/p[j])][r]-pre[j-1][r]);
}
}
}
}
int32_t main()
{
int t;
//freopen("k.in","r",stdin);
scanf("%lld",&t);
while(t--)
{
scanf("%lld",&n);
get_h(n);
printf("%lld\n",get_g(n,1)+1);
}
}
二平方定理:一个素数可以分解成两个平方数相加,当且仅当这个数字是2的倍数或者模4余1时
求莫比乌斯函数前缀和
int summu(int x)
{
if(x<size) return sumarr[x];
if(mp.count(x))return mp[x];
int ans=1;
for(int l=2,r;l<=x;l=r+1)
{
r=x/(x/l);
ans=(ans-1LL*(r-l+1)*summu(x/r)%mod+mod)%mod;
}
return mp[x]=ans;
}
注意:杜教筛通常需要线性筛处理出小数据的前缀和,以防止超时
Q:由BSGS::init(int p,int b,int BS_size_son,int BS_size_mon)预处理之后由BSGS::calc(N)可以计算满足 B k ≡ N ( m o d p ) B^k\equiv N(mod\ p) Bk≡N(mod p),复杂度为 O ( p B S s i z e s o n B S s i z e m o n + p q ( 1 − B S s i z e s o n B S s i z e m o n ) O(p^{\frac{BS_size_son}{BS_size_mon}}+p^{q(1-\frac{BS_size_son}{BS_size_mon})} O(pBSsizemonBSsizeson+pq(1−BSsizemonBSsizeson)其中q是需要求解的N的个数
namespace BSGS{
#define int long long
unordered_map<int,int> mp;
int loop,up;
int P,B;
int BS_size_son,BS_size_mon;
void init(int p,int b,int BS_size_son_,int BS_size_mon_)
{
BS_size_son=BS_size_son_;
BS_size_mon=BS_size_mon_;
P=p,B=b;
mp.clear();
up=ceil(pow(p,1.0*BS_size_son/BS_size_mon));
int t=1;
for(int i=0;i<=up;i++)
{
if(i==up) loop=t;
mp[t]=i;
t=1LL*t*b%p;
}
}
int calc(int N)
{
int m=ceil(pow(p,1.0-1.0*BS_size_son/BS_size_mon));
int obj=quick_pow(N,P-2,P);
for(int i=1;i<=m;i++)
{
obj=1LL*obj*loop%P;
if(mp.count(obj))
{
return 1LL*i*up-mp[obj];
}
}
return -1;
}
#undef int
}
注意:对于询问较多时,可以先预处理所有的大步中的数值,并通过合理地调整大步的大小使得复杂度合适
求解满足 a x ≡ b ( m o d p ) a^x\equiv b(mod\ p) ax≡b(mod p)的最小x,p不一定为素数
typedef long long ll;
unordered_map<ll,int> Hash;
int quick_pow(int a,int b,int mod){int ans=1;while(b){if(b&1) ans=1LL*ans*a%mod;a=1LL*a*a%mod;b>>=1;} return ans;}
int exbsgs(int a, int b, int p) {
a %= p; b %= p;
if(b == 1) return 0; int cnt = 0; ll t = 1;
if(a == 0) return b > 1 ? -1 : b == 0 && p > 1;
for(int g = __gcd(a, p); g != 1; g = __gcd(a, p)) {
if(b % g) return -1;
p /= g; b /= g; t = 1ll * t * (1ll * a / g % p) % p;
cnt++; if(b == t) return cnt;
}
Hash.clear(); int m = ceil(sqrt(p));
ll u = b; for(int i = 0; i < m; i++, u = 1ll * u * a % p) Hash[u] = i;
ll v = t, iv = quick_pow(a, m, p);
for(int i = 0; i <= m; i++) {
v = 1ll * v * iv % p;
if(Hash.count(v)) return (i + 1) * m - Hash[v] + cnt;
}
return -1;
}
Cipolla::calc(n,p)计算n在模p意义下开根号的值
namespace Cipolla{
LL w,P;
struct E{
LL x,y;
E(LL _x,LL _y):x(_x),y(_y){}
friend E operator *(E a,E b){
return E((a.x*b.x%P+a.y*b.y%P*w)%P,(a.x*b.y%P+a.y*b.x%P)%P);
}
};
inline E Pow(E x,int y){
E ret=E(1,0);
for(;y;y>>=1,x=x*x) if(y&1) ret=ret*x;
return ret;
}
LL calc(LL x,LL p){
P=p; x%=P;
if(x==0) return 0;
LL tmp=quick_pow(x,(p-1)/2,p);
if(tmp!=1) return -1;
while(1){
tmp=rand()%p;
LL cur=(tmp*tmp%P+P-x)%P;
if(quick_pow(cur,(p-1)/2,p)==p-1) break;
}
w=(tmp*tmp%P+P-x)%P;
E A=E(tmp,1);
return Pow(A,(p+1)/2).x;
}
}
求解 x 2 − n y 2 = 1 x^2-ny^2=1 x2−ny2=1的最小正整数根
ULL A,B,p[maxn],q[maxn],a[maxn],g[maxn],h[maxn];
int main()
{
int n;
for (int test=1;scanf("%d",&n) && n;++test)
{
printf("Case %d: ",test);
if (fabs(sqrt(n)-floor(sqrt(n)+1e-7))<=1e-7)
{
int a=(int)(floor(sqrt(n)+1e-7));
printf("%d %d\n",a,1);
}else
{
//求x^2-ny^2=1的最小正整数根,n不是完全平方数
p[1]=1;p[0]=0;
q[1]=0;q[0]=1;
a[2]=(int)(floor(sqrt(n)+1e-7));
g[1]=0;h[1]=1;
for (int i=2;i;++i)
{
g[i]=-g[i-1]+a[i]*h[i-1];
h[i]=(n-sqr(g[i]))/h[i-1];
a[i+1]=(g[i]+a[2])/h[i];
p[i]=a[i]*p[i-1]+p[i-2];
q[i]=a[i]*q[i-1]+q[i-2];
if (sqr((ULL)(p[i]))-n*sqr((ULL)(q[i]))==1)
{
A=p[i];B=q[i];
break;
}
}
cout << A << ' ' << B <<endl;
}
}
return 0;
}
namespace Polynomial_multiplication{
int n, m, rev[size << 2];
cp a[size << 2], b[size << 2];
void init(int len) {
for (n = 1, m = 0; n <= len; n <<= 1, m++);
for (int i = 0; i < n; ++i) {
rev[i] = rev[i >> 1] >> 1 | (i & 1) << (m - 1);
a[i] = cp(0, 0);
b[i] = cp(0, 0);
}
}
void builda(vector<int> x,int len){for(int i=0;i<=len;i++) a[i]=cp(x[i],0);}
void builda(int x[],int len){for(int i=0;i<=len;i++) a[i]=cp(x[i],0);}
void buildb(vector<int> x,int len){for(int i=0;i<=len;i++) b[i]=cp(x[i],0);}
void buildb(int x[],int len){for(int i=0;i<=len;i++) b[i]=cp(x[i],0);}
void fft(cp *a, int f) {
for (int i = 0; i < n; ++i)if (i < rev[i])swap(a[i], a[rev[i]]);
for (int i = 1; i < n; i <<= 1) {
double alpha = pi / i;
if (f == -1)alpha = -pi / i;
for (int k = 0; k < i; ++k) {
cp w = cp(cos(alpha*k), sin(alpha*k));
for (int j = k; j < n; j += (i << 1)) {
cp x = w * a[j + i];
a[j + i] = a[j] - x;
a[j] += x;
}
}
}
if(f==-1) for(int i=0;i<n;i++) a[i]/=n;
}
void calc(vector<int> &v,int len) {
fft(a, 1); fft(b, 1);
for (int i = 0; i < n; ++i)a[i] *= b[i];
fft(a, -1);
for(int i=0;i<=len;i++) v.push_back(LL(a[i].real()+0.5)%mod);
}
}
void ntt(int a[],int n,int inv)
{
int bit=0;
while((1<<bit)<n) bit++;
for(int i=0;i<n;i++)
{
rev[i]=(rev[i>>1]>>1)|((i&1)<<(bit-1));
if(i<rev[i]) swap(a[i],a[rev[i]]);
}
for(int mid=1;mid<n;mid*=2)
{
int e=quick_pow(g,(mod-1)/(2*mid));
for(int i=0;i<n;i+=mid*2)
{
int omega=1;
for(int j=0;j<mid;j++,omega=1LL*omega*e%mod)
{
int x=a[i+j],y=1LL*a[i+j+mid]*omega%mod;
a[i+j]=(x+y)%mod;a[i+j+mid]=(x-y+mod)%mod;
}
}
}
if(inv==1) return ;
int nv=quick_pow(n,mod-2);reverse(a+1,a+n);
for(int i=0;i<n;i++)a[i]=1LL*a[i]*nv%mod;
}
namespace polynomial{
const int mod=998244353;
const int g=3;
int rev[size<<2];
int A[size<<2],B[size<<2],C[size<<2],D[size<<2],E[size<<2],F[size<<2];
int vinv[size<<2];
void getinv(){vinv[1]=1;for(int i=2;i<(size<<2);i++) vinv[i]=1LL*(mod-mod/i)*vinv[mod%i]%mod;}
int quick_pow(int a,int b){int ans=1;while(b){if(b&1) ans=1LL*ans*a%mod;a=1LL*a*a%mod;b>>=1;} return ans;}
void NTT(int a[],int n,int inv)
{
for(int i=0;i<n;i++)
if(i<rev[i]) swap(a[i],a[rev[i]]);
for(int mid=1;mid<n;mid*=2)
{
int e=quick_pow(g,(mod-1)/(2*mid));
for(int i=0;i<n;i+=mid*2)
{
int omega=1;
for(int j=0;j<mid;j++,omega=1LL*omega*e%mod)
{
int x=a[i+j],y=1LL*a[i+j+mid]*omega%mod;
a[i+j]=(x+y)%mod;a[i+j+mid]=(x-y+mod)%mod;
}
}
}
if(inv==1) return ;
int nv=quick_pow(n,mod-2);reverse(a+1,a+n);
for(int i=0;i<n;i++)a[i]=1LL*a[i]*nv%mod;
}
void inv(int a[],int b[],int n)
{
b[0]=quick_pow(a[0],mod-2);
int len,lim;
for(len=1;len<(n<<1);len<<=1)
{
lim=len<<1;
for(int i=0;i<len;i++) A[i]=a[i],B[i]=b[i];
for(int i=0;i<lim;i++) rev[i]=rev[i>>1]>>1|((i&1)?len:0);
NTT(A,lim,1);NTT(B,lim,1);
for(int i=0;i<lim;i++) b[i]=((2-1LL*A[i]*B[i]%mod)*B[i]%mod+mod)%mod;
NTT(b,lim,-1);
for(int i=len;i<lim;i++) b[i]=0;
}
for(int i=0;i<len;i++) A[i]=B[i]=0;
for(int i=n;i<len;i++) b[i]=0;
}
void sqrt(int a[],int b[],int n)
{
b[0]=1;
int *A=C,*B=D,len,lim;
for(len=1;len<(n<<1);len<<=1)
{
lim=len<<1;
for(int i=0;i<len;i++) A[i]=a[i];
inv(b,B,lim>>1);
for(int i=0;i<lim;i++) rev[i]=rev[i>>1]>>1|((i&1)?len:0);
NTT(A,lim,1);NTT(B,lim,1);
for(int i=0;i<lim;i++) A[i]=1LL*A[i]*B[i]%mod;
NTT(A,lim,-1);
for(int i=0;i<len;i++) b[i]=1LL*(b[i]+A[i])%mod*(mod+1)/2%mod;
for(int i=len;i<lim;i++) b[i]=0;
}
for(int i=0;i<len;i++) A[i]=B[i]=0;
for(int i=n;i<len;i++) b[i]=0;
}
void differential(int a[],int b[],int n)
{
for(int i=0;i<n-1;i++)
b[i]=1LL*a[i+1]*(i+1)%mod;
b[n-1]=0;
}
void integral(int a[],int b[],int n)
{
for(int i=1;i<n+1;i++)
b[i]=1LL*a[i-1]*vinv[i]%mod;
b[0]=0;
}
void ln(int a[],int b[],int n)
{
int *A=C,*B=D,len=1;
inv(a,B,n);
differential(a,A,n);
while(len<(n<<1)) len<<=1;
NTT(A,len,1),NTT(B,len,1);
for(int i=0;i<len;i++) A[i]=1LL*A[i]*B[i]%mod;
NTT(A,len,-1);
integral(A,b,n);
}
void exp(int a[],int b[],int n)
{
b[0]=1;
int *A=E,*B=F,len,lim;
for(len=1;len<(n<<1);len<<=1)
{
lim=len<<1;
for(int i=0;i<len;i++) A[i]=b[i];
ln(b,B,lim>>1);
B[0]=(1-B[0]+a[0]+mod)%mod;
for(int i=1;i<len;i++) B[i]=(-B[i]+a[i]+mod)%mod;
for(int i=0;i<lim;i++) rev[i]=rev[i>>1]>>1|((i&1)?len:0);
NTT(A,lim,1);NTT(B,lim,1);
for(int i=0;i<lim;i++) b[i]=1LL*A[i]*B[i]%mod;
NTT(b,lim,-1);
for(int i=len;i<lim;i++) b[i]=0;
}
for(int i=0;i<len;i++) A[i]=B[i]=0;
for(int i=n;i<len;i++) b[i]=0;
}
}
已知 G ( x ) G(x) G(x),求解 G ( F ( x ) ) ≡ 0 ( m o d x n ) G(F(x))\equiv 0(mod\ x^n) G(F(x))≡0(mod xn)
假设存在一个函数H使得有 G ( H ( x ) ) ≡ 0 ( m o d x n 2 ) G(H(x))\equiv 0(mod\ x^{n\over2}) G(H(x))≡0(mod x2n)
对G(F(x))在H(x)处泰勒展开
由于 G ( H ( x ) ) ≡ 0 ( m o d x n 2 ) G(H(x))\equiv 0(mod\ x^{n\over 2}) G(H(x))≡0(mod x2n)代表了F(x)的前 n 2 n\over2 2n项就是H(x)故也就有
( F ( x ) − H ( x ) ) 2 ≡ 0 ( m o d x n ) (F(x)-H(x))^2\equiv 0(mod\ x^n) (F(x)−H(x))2≡0(mod xn)
故泰勒展开也就可以写作
G ( F ( x ) ) ≡ G ( H ( x ) ) + G ′ ( H ( x ) ) ( F ( x ) − H ( x ) ) ≡ 0 ( m o d x n ) G(F(x))\equiv G(H(x))+G'(H(x))(F(x)-H(x))\equiv 0(mod\ x^n) G(F(x))≡G(H(x))+G′(H(x))(F(x)−H(x))≡0(mod xn)
移项变换之后就有
F ( x ) ≡ H ( x ) − G ( H ( x ) ) G ′ ( H ( x ) ) ( m o d x n ) F(x)\equiv H(x)-\frac{G(H(x))}{G'(H(x))}(mod\ x^n) F(x)≡H(x)−G′(H(x))G(H(x))(mod xn)
就可以通过不断缩小n得到答案
solve(1,1,n)求
( x + a S 1 ) ( x + a S 2 ) . . . ( x + a S n ) (x+a^{S_1})(x+a^{S_2})...(x+a^{S_n}) (x+aS1)(x+aS2)...(x+aSn)
#include
using namespace std;
typedef long long LL;
typedef long long ll;
const double pi=acos(-1);
typedef complex<double> cp;
int n,a,q;
const int mod=100003;
const int size=1e5+5;
vector<int> co[size<<2];
cp x[size],y[size];
int b[size],s[size];
int quick_pow(int a,int b){int ans=1;while(b){if(b&1) ans=1LL*a*ans%mod;a=1LL*a*a%mod;b>>=1;} return ans;}
int fac[size];
int invfac[size];
void init()
{
fac[0]=1;
for(int i=1;i<=n;i++) fac[i]=1LL*fac[i-1]*i%mod;
invfac[n]=quick_pow(fac[n],mod-2);
for(int i=n-1;i>=0;i--) invfac[i]=1LL*invfac[i+1]*(i+1)%mod;
}
namespace Polynomial_multiplication{
int n, m, rev[size << 2];
cp a[size << 2], b[size << 2];
void init(int len) {
for (n = 1, m = 0; n <= len; n <<= 1, m++);
for (int i = 0; i < n; ++i) {
rev[i] = rev[i >> 1] >> 1 | (i & 1) << (m - 1);
a[i] = cp(0, 0);
b[i] = cp(0, 0);
}
}
void builda(vector<int> x,int len){for(int i=0;i<=len;i++) a[i]=cp(x[i],0);}
void builda(int x[],int len){for(int i=0;i<=len;i++) a[i]=cp(x[i],0);}
void buildb(vector<int> x,int len){for(int i=0;i<=len;i++) b[i]=cp(x[i],0);}
void buildb(int x[],int len){for(int i=0;i<=len;i++) b[i]=cp(x[i],0);}
void fft(cp *a, int f) {
for (int i = 0; i < n; ++i)if (i < rev[i])swap(a[i], a[rev[i]]);
for (int i = 1; i < n; i <<= 1) {
double alpha = pi / i;
if (f == -1)alpha = -pi / i;
for (int k = 0; k < i; ++k) {
cp w = cp(cos(alpha*k), sin(alpha*k));
for (int j = k; j < n; j += (i << 1)) {
cp x = w * a[j + i];
a[j + i] = a[j] - x;
a[j] += x;
}
}
}
if(f==-1) for(int i=0;i<n;i++) a[i]/=n;
}
void calc(vector<int> &v,int len) {
fft(a, 1); fft(b, 1);
for (int i = 0; i < n; ++i)a[i] *= b[i];
fft(a, -1);
for(int i=0;i<=len;i++) v.push_back(LL(a[i].real()+0.5)%mod);
}
}
void solve(int id,int l,int r)
{
if(l==r)
{
co[id].push_back(1);
co[id].push_back(b[l]);
return ;
}
int mid=(l+r)/2;
solve(id<<1,l,mid);
solve(id<<1|1,mid+1,r);
Polynomial_multiplication::init(r-l+1);
Polynomial_multiplication::builda(co[id<<1],mid-l+1);
Polynomial_multiplication::buildb(co[id<<1|1],r-mid);
Polynomial_multiplication::calc(co[id],r-l+1);
}
int ans[size];
inline LL combi(int k,int n){return k>n?0:1LL*fac[n]*invfac[k]%mod*invfac[n-k]%mod;}
int main()
{
scanf("%d%d%d",&n,&a,&q);
init();
for(int i=1;i<=n;i++) scanf("%d",&s[i]);
for(int i=1;i<=n;i++) b[i]=quick_pow(a,s[i]%(mod-1));
solve(1,1,n);
int inva_1=quick_pow(a-1,mod-2);
for(int i=1;i<=n;i++) ans[i]=(co[1][i]-combi(i,n)+mod)%mod*inva_1%mod;
for(int i=1;i<=q;i++)
{
int k;
scanf("%d",&k);
printf("%d\n",ans[k]);
}
return 0;
}
1 + x + x 2 2 ! + x 3 3 + . . . = e x 1 − x + x 2 2 ! − x 3 3 + . . = e − x 1 + x 2 2 ! + x 4 4 ! + x 6 6 ! + . . = e x + e − x 2 x + x 3 3 ! + x 5 5 ! + x 7 7 ! + . . = e x − e − x 2 x − 1 2 x 2 + 1 3 x 3 + . . . = l n ( 1 + x ) x − 1 3 ! x 3 + 1 5 ! x 5 + . . . = s i n ( x ) x + 1 2 x 3 3 + 1 ⋅ 3 2 ⋅ 4 x 5 5 + 1 ⋅ 3 ⋅ 5 2 ⋅ 4 ⋅ 6 x 7 7 + . . . = a r c s i n ( x ) 1 − 1 2 ! x 2 + 1 4 ! x 4 + . . . = c o s ( x ) 1 + a 1 ! x + a ( a − 1 ) 2 ! x 2 + a ( a − 1 ) ( a − 2 ) 3 ! x 3 + . . . = ( x + 1 ) a \begin{aligned} &1+x+\frac{x^2}{2!}+\frac{x^3}{3}+...=e^x\\ &1-x+\frac{x^2}{2!}-\frac{x^3}{3}+..=e^{-x}\\ &1+\frac{x^2}{2!}+\frac{x^4}{4!}+\frac{x^6}{6!}+..=\frac{e^x+e^{-x}}{2}\\ &x+\frac{x^3}{3!}+\frac{x^5}{5!}+\frac{x^7}{7!}+..=\frac{e^x-e^{-x}}{2}\\ &x-\frac{1}{2}x^2+\frac{1}{3}x^3+...=ln(1+x)\\ &x-\frac{1}{3!}x^3+\frac{1}{5!}x^5+...=sin(x)\\ &x+\frac{1}{2}\frac{x^3}{3}+\frac{1\cdot3}{2\cdot 4}\frac{x^5}{5}+\frac{1\cdot3\cdot5}{2\cdot4\cdot6}\frac{x^7}{7}+...=arcsin(x)\\ &1-\frac{1}{2!}x^2+\frac{1}{4!}x^4+...=cos(x)\\ &1+\frac{a}{1!}x+\frac{a(a-1)}{2!}x^2+\frac{a(a-1)(a-2)}{3!}x^3+...=(x+1)^a \end{aligned} 1+x+2!x2+3x3+...=ex1−x+2!x2−3x3+..=e−x1+2!x2+4!x4+6!x6+..=2ex+e−xx+3!x3+5!x5+7!x7+..=2ex−e−xx−21x2+31x3+...=ln(1+x)x−3!1x3+5!1x5+...=sin(x)x+213x3+2⋅41⋅35x5+2⋅4⋅61⋅3⋅57x7+...=arcsin(x)1−2!1x2+4!1x4+...=cos(x)1+1!ax+2!a(a−1)x2+3!a(a−1)(a−2)x3+...=(x+1)a
已知n次多项式前n+1项,求多项式其余任意项数,和已知前n+2项,求前缀和
namespace lagrange{//calculate k-degree polynomial Prefix sum of n or k_degree poly' value of n
const int maxk=1000+5;//the order of the polynomial
int coeff[maxk];int suf[maxk],bef[maxk];
int mod;
int k;
void init_sum(int k_,int f[],int mod_) //need prefix k+2' value
{
mod=mod_;
k=k_+2;
for(int i=1;i<=k;i++) coeff[i]=f[i];
coeff[0]=0;
for(int i=1;i<=k;i++) coeff[i]=(coeff[i-1]+coeff[i])%mod;
}
void init_val(int k_,int f[],int mod_) //need prefix k+1's value
{
mod=mod_;
k=k_+1;
for(int i=1;i<=k;i++) coeff[i]=f[i];
}
int calc(int n)
{
if(n==0) return 0;
if(n<=k) return coeff[n];
bef[0] = suf[0] = 1;
for (int i = 1; i <= k ; ++i) {
bef[i] = 1LL*bef[i - 1] * ((n - i) % mod) % mod;
suf[i] = 1LL*suf[i - 1] * ((n + i - k - 1) % mod) % mod;
}
int res = 0;
for (int i = 1; i <= k ; ++i) {
int s = 1LL*coeff[i] * bef[i - 1] % mod * suf[k - i ] % mod * inv[i - 1] % mod * inv[k - i] % mod;// is facinv
if ((k - i) & 1)s = -s;
res += s;
res = (res % mod + mod) % mod;
}
return res;
}
}
对于n-1次多项式已知n个不相邻的点的点值,则可以由
f ( X ) = ∑ i = 0 n − 1 y i ∏ j ≠ i X − x j x i − x j f(X)=\sum_{i=0}^{n-1}y_i\prod_{j\not=i} \frac{X-x_j}{x_i-x_j} f(X)=i=0∑n−1yij=i∏xi−xjX−xj
得到X处的值
求分子分母小于n的且分数值大于up的最简分数
Frac SBtree(Frac up)
{
Frac L=Frac(0,1),R=Frac(1,0);
LL x=up.son,y=up.mon;
Frac mid(1,1);
Frac ans=Frac(1,1);
while(x!=y&&mid.son<=n&&mid.mon<=n)
{
// cout<
if(mid.son*up.mon>mid.mon*up.son) ans=mid;
if(x<y)
{
R=mid;
mid=Frac(L.son+R.son,L.mon+R.mon);
y-=x;
}
else
{
L=mid;
mid=Frac(L.son+R.son,L.mon+R.mon);
x-=y;
}
}
return ans;
}
整数类型
int Gauss(int equ,int var)//equ:表示多少可变元,var: 表示多少列
{
int k,max_r,col = 0,ta,tb;
int LCM,temp,num = 0,free_index;
for(int i=0;i<=var;i++)
{
x[i]=0;
free_x[i]=true;
}
for(k=0;k<equ && col<var;k++,col++)
{
max_r=k;
for(int i=k+1;i<equ;i++)
if(abs(a[i][col])>abs(a[max_r][col])) max_r=i;
if(max_r!=k)// 与第k行交换.
for(int j=k;j<var+1;j++) swap(a[k][j],a[max_r][j]);
if(a[k][col]==0)// 说明该col列第k行以下全是0了,则处理当前行的下一列
{
free_x[num++] = col; k--;
continue;
}
for(int i=k+1;i<equ;i++)
{// 枚举要删去的行.
if(a[i][col]!=0)
{
LCM=lcm(abs(a[i][col]),abs(a[k][col]));
ta=LCM/abs(a[i][col]);
tb=LCM/abs(a[k][col]);
if(a[i][col]*a[k][col]<0) tb=-tb;//异号的情况是相加
for(int j=col;j<var+1;j++) a[i][j]=a[i][j]*ta-a[k][j]*tb;
}
}
}
//无解
for(int i=k; i<equ;i++) if(a[i][col]!=0) return -1;
//无穷解
if(k<var) return var-k; // 自由变元有var - k个.
//唯一解
for (int i = var - 1; i >= 0; i--)
{
temp = a[i][var];
for(int j = i + 1; j<var; j++) if(a[i][j] != 0) temp-=a[i][j]*x[j];
if(temp%a[i][i]!=0) return -2; // 说明有浮点数解,但无整数解.
x[i]=temp/a[i][i];
}
return 0;
}
b.浮点数类型(HihoCoder1195)
using namespace std;
typedef long long ll;
ll read()
{
ll x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return x*f;
}
int n,m;
double s[N][N],a[N][N],ans[N];
const double EPS=1e-10;
int Gauss_Elimination()
{
int k=1,col=1;
for(;col<=n&&k<=m;col++,k++)
{
int r=k;
for(int i=k+1;i<=m;i++) if(fabs(a[i][col])>fabs(a[r][col])) r=i;
if(fabs(a[r][col])<EPS) { k--;continue; }//自由元
if(r!=k) swap(a[r],a[k]);
for(int i=k+1;i<=m;i++)
{
if(fabs(a[i][col])>EPS)
{
double t=a[i][col]/a[k][col];
for(int j=col;j<=n+1;j++) a[i][j]-=a[k][j]*t;
//当前行为k,当前列为col,要化成上三角矩阵,所以这里将后面的式子中当前列全部变为0,
//做法就是将第k行化为第col列与当前行系数相同的式子,然后当前行依次减掉它。
}
}
}
for(int i=k;i<=m;i++) if(fabs(a[i][n+1])>EPS) return -1; //无解
if(k<=n) return n-k+1; //返回自由元个数(有多解)
for(int i=n;i;i--)
{
for(int j=i+1;j<=n;j++) a[i][n+1]-=a[i][j]*a[j][n+1];
a[i][n+1]/=a[i][i];
} //回带过程
return 0;
}
int main()
{
n=read();m=read();
for(int i=1;i<=m;i++)
for(int j=1;j<=n+1;j++) a[i][j]=read();
int t=Gauss_Elimination();
if(t<0) puts("No solutions");
else if(t>0) puts("Many solutions");
else for(int i=1;i<=n;i++) printf("%d\n",int(a[i][n+1]+0.5));
return 0;
}
C.异或类型
(HihoCoder1196)
void Gauss_Elimination()
{
int k=1,col=1;
for(;k<=n&&col<=n;k++,col++)
{
int r=k;
for(int i=k;i<=n;i++) if(a[i][col]==1) {
r=i;break;
}
if(!a[r][col]) {k--;continue;}
if(r!=k) swap(a[r],a[k]);
for(int i=k+1;i<=n;i++)
{
if(!a[i][col]) continue;
for(int j=col;j<=n+1;j++) a[i][j]^=a[k][j];
//和解线性方程组有些不同,但都是化成上三角形式,想想发现其实就是将两个式子合并,将当前列化为0的新等式。
}
}
for(int i=n;i;i--)
{
for(int j=i+1;j<=n;j++) a[i][n+1]^=(a[j][n+1]*a[i][j]);//只有两个都为1才算。
//这里并不需要管a[i][i],输出看看发现全是1.
}
int sum=0;
for(int i=1;i<=n;i++) if(a[i][n+1]) sum++;
printf("%d\n",sum);
for(int i=1;i<=n;i++) if(a[i][n+1]) Get(i);
}
异或二:
int a[nmax][nmax];
int x[nmax];
int hashback[nmax][nmax];
int free_x[nmax];
char mp[nmax][nmax];
int ans1,ans2,equ,var;
int Gauss()
{
int max_r;
int col=0,num = 0;
int k;
for(int i = 0;i<=var;++i) x[i] = free_x[i] = 0;
for(k = 0;k < equ && col < var;k++,col++)
{
max_r=k;
for(int i=k+1;i<equ;i++) if(abs(a[i][col])>abs(a[max_r][col])) max_r=i;
if(max_r!=k) for(int j=k ;j<var+1;j++) swap(a[k][j],a[max_r][j]);
if(a[k][col]==0)
{
free_x[num++] = col;
k--; continue;
}
for(int i=k+1;i<equ;i++)
{
if(a[i][col]!=0)
for(int j=col;j<var+1;j++) a[i][j]^=a[k][j];
}
}
for(int i = k;i<equ;++i) if(a[i][col] != 0) return -1;
if(k < var) return var - k;
for(int i = var - 1; i >= 0; i--)
{
x[i]=a[i][var];
for(int j = i + 1; j < var; j++) x[i] ^= ( a[i][j] && x[j]);
}
return 0;
}
模数不为素数
int Gauss()
{
int ans = 1;
for(int i = 1; i < tot; i ++)
{
for(int j = i + 1; j < tot; j ++)
while(f[j][i])
{
int t = f[i][i] / f[j][i];
for(int k = i; k < tot; k ++)
f[i][k] = (f[i][k] - t * f[j][k] + mod) % mod;
swap(f[i], f[j]);
ans = - ans;
}
ans = (ans * f[i][i]) % mod;
}
return (ans + mod) % mod;
}
模数为素数
int gaussian(){
int s=n-1,res=1;
for(int i=1;i<=s;i++){
if(!a[i][i]){
int t;
for(t=i+1;t<=s&&!a[t][i];t++);
if(t>s) return 0;
for(int j=i;j<=s;j++) swap(a[i][j],a[t][j]);
res=-res;
}
int inv=ksm(a[i][i],MOD-2);
for(int j=i+1;j<=s;j++){
int t=mul(a[j][i],inv);
for(int k=i;k<=s;k++)
a[j][k]=plus(a[j][k],-mul(a[i][k],t));
}
}
for(int i=1;i<=s;i++) res=mul(res,a[i][i]);
return res;
}
1.C(n,r)=C(n-1,r)+C(n-1,r-1)
2.C(n,0)+C(n+1,1)+C(n+2,2)+ …+C(n+r,r)=C(n+r+1,r)
**3.C(n,l)C(l,r)=C(n,r)C(n-r,l-r)
4.C(n,0)+C(n,1)+…+C(n,n-1)+C(n,n)=2n
5.C(n,0)-C(n,1)+C(n,2)-…±C(n,n)=0
**6.C(m+n,r)=C(m,0)*C(n,r)+C(m,1)C(n,r-1)+…+C(m,r)C(n,0)
**7.C(m+n,m)=C(m,0)*C(n,0)+C(m,1)C(n,1)+…+C(m,m)C(n,m)
8.C(r,r)+C(r+1,r)+C(r+2,r)….+C(n,r)=C(n+1,r+1)
模数为素数时Lucas
ll pow(ll a, ll b, ll m)
{
ll ans = 1;
a %= m;
while(b)
{
if(b & 1)ans = (ans % m) * (a % m) % m;
b /= 2;
a = (a % m) * (a % m) % m;
}
ans %= m;
return ans;
}
ll inv(ll x, ll p)//x关于p的逆元,p为素数
{
return pow(x, p - 2, p);
}
ll C(ll n, ll m, ll p)//组合数C(n, m) % p
{
if(m > n)return 0;
ll up = 1, down = 1;//分子分母;
for(int i = n - m + 1; i <= n; i++)up = up * i % p;
for(int i = 1; i <= m; i++)down = down * i % p;
return up * inv(down, p) % p;
}
ll Lucas(ll n, ll m, ll p)
{
if(m == 0)return 1;
return C(n % p, m % p, p) * Lucas(n / p, m / p, p) % p;
}
模数为非素数时EXLucas
#include
using namespace std;
typedef long long ll;
const int maxn = 1e6 + 10;
const int mod = 1e9 + 7;
ll pow(ll a, ll b, ll m)
{
ll ans = 1;
a %= m;
while(b)
{
if(b & 1)ans = (ans % m) * (a % m) % m;
b /= 2;
a = (a % m) * (a % m) % m;
}
ans %= m;
return ans;
}
ll extgcd(ll a, ll b, ll& x, ll& y)
//求解ax+by=gcd(a, b)
//返回值为gcd(a, b)
{
ll d = a;
if(b)
{
d = extgcd(b, a % b, y, x);
y -= (a / b) * x;
}
else x = 1, y = 0;
return d;
}
ll mod_inverse(ll a, ll m)
//求解a关于模上m的逆元
//返回-1表示逆元不存在
{
ll x, y;
ll d = extgcd(a, m, x, y);
return d == 1 ? (m + x % m) % m : -1;
}
ll Mul(ll n, ll pi, ll pk)//计算n! mod pk的部分值 pk为pi的ki次方
//算出的答案不包括pi的幂的那一部分
{
if(!n)return 1;
ll ans = 1;
if(n / pk)
{
for(ll i = 2; i <= pk; i++) //求出循环节乘积
if(i % pi)ans = ans * i % pk;
ans = pow(ans, n / pk, pk); //循环节次数为n / pk
}
for(ll i = 2; i <= n % pk; i++)
if(i % pi)ans = ans * i % pk;
return ans * Mul(n / pi, pi, pk) % pk;//递归求解
}
ll C(ll n, ll m, ll p, ll pi, ll pk)//计算组合数C(n, m) mod pk的值 pk为pi的ki次方
{
if(m > n)return 0;
ll a = Mul(n, pi, pk), b = Mul(m, pi, pk), c = Mul(n - m, pi, pk);
ll k = 0, ans;//k为pi的幂值
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;
ans = a * mod_inverse(b, pk) % pk * mod_inverse(c, pk) % pk * pow(pi, k, pk) % pk;//ans就是n! mod pk的值
ans = ans * (p / pk) % p * mod_inverse(p / pk, pk) % p;//此时用剩余定理合并解
return ans;
}
ll Lucas(ll n, ll m, ll p)
{
ll x = p;
ll ans = 0;
for(ll i = 2; i <= p; i++)
{
if(x % i == 0)
{
ll pk = 1;
while(x % i == 0)pk *= i, x /= i;
ans = (ans + C(n, m, p, i, pk)) % p;
}
}
return ans;
}
int main()
{
ll n, m, p;
while(cin >> n >> m >> p)
{
cout<<Lucas(n, m, p)<<endl;
}
return 0;
}
Q:要求构造长度为n的序列 { a n } \{a_n\} {an}(令其和序列为 S n S_n Sn)使得有
{ ∀ i S i ≥ 0 ∀ i a i = 0 o r 1 o r − 1 l ≤ S n ≤ r \begin{cases}\forall_i \ S_i\ge 0\\\forall_i a_i=0\ or\ 1\ or -1\\l\ \le S_n\le r\end{cases} ⎩⎪⎨⎪⎧∀i Si≥0∀iai=0 or 1 or−1l ≤Sn≤r
问可以构造多少这样的序列.由于最终的答案可能很大,因此对p取模A:
考虑现在有i个0,则先将i个0分配到序列中,剩余未设定的数的数量设为m.则在着m个未设定数字中只有1与-1.对一确定的长度m,要让其所有的前缀和大于0,且有最终值介于lr之间,设最终达到的值为2x.设m=2k,则1有k+x,-1有k-x.只考虑最终的值为x则有组合数 C 2 k k + x C_{2k}^{k+x} C2kk+x。但是这并不是最终答案,我们还需要减去其中会小于0的情况.如果其中存在少于0的部分,则必然存在某个位置2h+1此时有h+1个-1,h个1,而剩下的序列也就会剩下 k + x − h k+x-h k+x−h个1, k − x − h − 1 k-x-h-1 k−x−h−1个-1,将-1与1数量翻转,则整个序列将存在 k + x + 1 k+x+1 k+x+1个-1. k − x − 1 k-x-1 k−x−1个1,则有少于0的前缀和的组合数即为 C 2 k k + x + 1 C_{2k}^{k+x+1} C2kk+x+1。则最终答案介于lr之间的组合数就是 ∑ x = l r ( C 2 k k + x − C 2 k k + x + 1 ) \sum_{x=l}^{r}(C_{2k}^{k+x}-C_{2k}^{k+x+1}) ∑x=lr(C2kk+x−C2kk+x+1)则最终的求和公式即为 C 2 k k + ( l + 1 ) / 2 − C 2 k k + r / 2 + 1 C_{2k}^{k+(l+1)/2}-C_{2k}^{k+r/2+1} C2kk+(l+1)/2−C2kk+r/2+1以上的其实可以算作是卡特兰数的一个拓展.而在组合数的计算中,由于需要取模故需要求逆元,但是,并不能保证模数与阶乘互素,因此需要对阶乘提出所有与模数的公因数.将其额外提出运算,而剩余部分直接做逆元.
#include
using namespace std;
#define int long long
typedef long long LL;
const int size=1e5+5;
int n,p,l,r;
int tot;
int prime[45];
int fac[size],inv[size];
int tim[size][45];
LL quick_pow(LL a,LL b)
{
LL ans=1;
while(b)
{
if(b&1) ans=ans*a%p;
a=a*a%p;
b>>=1;
}
return ans;
}
int phi(int n)
{
int res=n;
for(int i=2;i*i<=n;i++)
{
if(n%i==0)
{
res=res-res/i;
do n/=i;
while(n%i==0);
}
}
if(n>1)
res=res-res/n;
return res;
}
void init()
{
int temp=p;
for(int i=2;i*i<=temp;i++)
{
if(temp%i==0)
{
prime[tot++]=i;
do temp/=i;
while(temp%i==0);
}
}
if(temp>1) prime[tot++]=temp;
fac[0]=fac[1]=1;
inv[0]=inv[1]=1;
int phip=phi(p);
memset(tim,0,sizeof(tim));
for(int i=2;i<=n;i++)
{
int x=i;
for(int j=0;j<tot;j++)
{
tim[i][j]=tim[i-1][j];
while(x%prime[j]==0) x/=prime[j],tim[i][j]++;
}
fac[i]=fac[i-1]*x%p;
inv[i]=quick_pow(fac[i],phip-1);
}
}
int combi(int n,int m)
{
if(m>n) return 0;
if(m<0) return 0;
if(m==0) return 1;
LL ans=(fac[n]*inv[n-m]%p)*inv[m]%p;
for(int i=0;i<tot;i++)
{
ans=ans*quick_pow(prime[i],tim[n][i]-tim[n-m][i]-tim[m][i])%p;
}
return ans;
}
int32_t main()
{
scanf("%lld%lld%lld%lld",&n,&p,&l,&r);
LL ans=0;
init();
for(int i=0;i<=n;i++)
{
int m=n-i;
ans=(ans+combi(n,i)*((-combi(m,(m+min(r,m))/2+1)+combi(m,(m+l+1)/2)+p)%p))%p;
}
printf("%lld\n",ans);
}
设 T n , k T_{n,k} Tn,k为n个有标号点分成k个连通块的的分割种数,其中节点1,2,3,…k属于不同的联通块
T n , k = k n n − k − 1 T_{n,k}=k\ n^{n-k-1} Tn,k=k nn−k−1
所有的普吕弗序列和树唯一相对应,且普吕弗序列中点出现的次数为这个点在树中的度数-1,因此,在给出了一棵树的度数之后想要求得树的数量,就可以转化为,求序列的组合的数量,设无度数要求的点数是num,有要求的点数是poi,有要求的点在序列中出现的次数为sum,点的总数是n,那么答案就是:
a n s = A n − 2 s u m ∏ i = 1 p o i ( d u [ i ] − 1 ) ! ∗ n u m n − s u m − 2 ans= \frac {A^{sum}_{n-2}}{\prod_{i=1}^{poi}(du[i]-1)!}*num^{n-sum-2} ans=∏i=1poi(du[i]−1)!An−2sum∗numn−sum−2
Q:对于给定的一幅图,要求从中选出一些边,使得构成最小生成树,问有多少种构造方法?
A:当i=j时, BBTij=vi的度数;而当i≠j时,如果存在边(vi,vj),那么BBTij=-1,否则BBTij=0。由此构建出图的Kirchhoff矩阵。则生成树的数量就是这个矩阵的任意n-1阶主子式行列式的值
Q:给出一个p和x要求求出最小的b满足
a ≡ b x ( m o d p ) a\equiv bx(mod\ p) a≡bx(mod p)A:先对原式进行一些转化
a ≡ b x ( m o d p ) a = b x − p c ( c ∈ Z ) ∵ 0 ≤ a < b → 0 ≤ b x − p c < b → p x ≤ b c < p x − 1 \begin{aligned} a&\equiv bx(mod\ p)\\ a&=bx-pc(c\in Z)\\ \because &0\le aaa∵→→≡bx(mod p)=bx−pc(c∈Z)0≤a<b0≤bx−pc<bxp≤cb<x−1p
原问题就转化成了一个经典问题,求满足值在所给的两分数之间时,最小的分子分母是多少。设 ⌈ p x ⌉ = d \left\lceil\frac{p}{x}\right\rceil=d ⌈xp⌉=d,当 ⌊ p x − 1 ⌋ ≥ d \left\lfloor\frac{p}{x-1}\right\rfloor\ge d ⌊x−1p⌋≥d时,显然有b=d,c=1为最优解,但是当不满足这个条件时,首先可以发现 p x \frac{p}{x} xp与 p x − 1 \frac{p}{x-1} x−1p之间的差值必然小于1,由此
p x − ( d − 1 ) ≤ b c − ( d − 1 ) < p x − 1 − ( d − 1 ) \begin{aligned} \frac{p}{x}-(d-1)\le \frac{b}{c}-(d-1)<\frac{p}{x-1}-(d-1) \end{aligned} xp−(d−1)≤cb−(d−1)<x−1p−(d−1)
此时可以发现不等式外侧的两个值都变成了真分数,只要对其作倒数就又变成了假分数则又可以进行上述操作,最终到达满足条件的答案再倒退回来就是答案
#include
using namespace std;
typedef long long LL;
LL p,a;
//solve "pa/pb
void solve(LL pa,LL pb,LL qa,LL qb,LL &x,LL &y)
{
LL z=(pa+pb-1)/pb;
if(z<=qa/qb){
x=z;y=1;
return ;
}
pa-=(z-1)*pb;qa-=(z-1)*qb;
solve(qb,qa,pb,pa,y,x);
x+=(z-1)*y;
}
int main()
{
int t;
scanf("%d",&t);
LL x,y;
while(t--)
{
scanf("%lld%lld",&p,&a);
solve(p,a,p,a-1,x,y);
printf("%lld/%lld\n",x*a-p*y,x);
}
}
给出年月日求是星期几?(只适用于1582.10.15以后)
int zeller(int y,int m,int d) {
if (m<=2) y--,m+=12;
int c=y/100;
y%=100;
int w=((c>>2)-(c<<1)+y+(y>>2)+(13*(m+1)/5)+d-1)%7;
if (w<0) w+=7;
return(w);
}
BM
(解线性递推式)
using namespace std;
#define rep(i,a,n) for (int i=a;i
#define per(i,a,n) for (int i=n-1;i>=a;i--)
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define SZ(x) ((int)(x).size())
typedef vector<int> VI;
typedef long long ll;
typedef pair<int,int> PII;
const ll mod=1000000007;
ll powmod(ll a,ll b) {ll res=1;a%=mod; assert(b>=0); for(;b;b>>=1) { if(b&1)res=res*a%mod; a=a*a%mod; } return res; }
ll _,n;
namespace linear_seq {
const int N=10010;
ll res[N],base[N],_c[N],_md[N];
vector<ll> Md;
void mul(ll *a,ll *b,int k)
{
rep(i,0,k+k) _c[i]=0;
rep(i,0,k) if (a[i]) rep(j,0,k) _c[i+j]= (_c[i+j]+a[i]*b[j])%mod;
for (int i=k+k-1;i>=k;i--) if (_c[i])
rep(j,0,SZ(Md)) _c[i-k+Md[j]]=(_c[i-k+Md[j]]-_c[i]*_md[Md[j]])%mod;
rep(i,0,k) a[i]=_c[i];
}
int solve(ll n,VI a,VI b)
{
ll ans=0,pnt=0;
int k=SZ(a);
assert(SZ(a)==SZ(b));
rep(i,0,k) _md[k-1-i]=-a[i];_md[k]=1;
Md.clear();
rep(i,0,k) if (_md[i]!=0) Md.push_back(i);
rep(i,0,k) res[i]=base[i]=0;
res[0]=1;
while ((1ll<<pnt)<=n) pnt++;
for (int p=pnt;p>=0;p--)
{
mul(res,res,k);
if ((n>>p)&1)
{
for (int i=k-1;i>=0;i--) res[i+1]=res[i];res[0]=0;
rep(j,0,SZ(Md)) res[Md[j]]=(res[Md[j]]-res[k]*_md[Md[j]])%mod;
}
}
rep(i,0,k) ans=(ans+res[i]*b[i])%mod;
if (ans<0) ans+=mod;
return ans;
}
VI BM(VI s) {
VI C(1,1),B(1,1);
int L=0,m=1,b=1;
rep(n,0,SZ(s)) {
ll d=0;
rep(i,0,L+1) d=(d+(ll)C[i]*s[n-i])%mod;
if (d==0) ++m;
else if (2*L<=n) {
VI T=C;
ll c=mod-d*powmod(b,mod-2)%mod;
while (SZ(C)<SZ(B)+m) C.pb(0);
rep(i,0,SZ(B)) C[i+m]=(C[i+m]+c*B[i])%mod;
L=n+1-L; B=T; b=d; m=1;
} else {
ll c=mod-d*powmod(b,mod-2)%mod;
while (SZ(C)<SZ(B)+m) C.pb(0);
rep(i,0,SZ(B)) C[i+m]=(C[i+m]+c*B[i])%mod;
++m;
}
}
return C;
}
int gao(VI a,ll n) {
VI c=BM(a);
c.erase(c.begin());
rep(i,0,SZ(c)) c[i]=(mod-c[i])%mod;
return solve(n,c,VI(a.begin(),a.begin()+SZ(c)));
}
};
int T;
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%lld",&n);
vector<int>v;
//关系式前几项,一般10项
v.push_back(a[i]);
v.push_back(a[2]);
//........
v.push_back(a[x]);
printf("%lld\n",linear_seq::gao(v,n-1)%mod);
}
}
广义BM
求线性递推式的最短通项
#include
using namespace std;
typedef long long LL;
const int mod=1e9;
struct LinearRecurrence {
using vec = std::vector<LL>;
static void extand(vec &a, size_t d, LL value = 0) {
if (d <= a.size()) return;
a.resize(d, value);
}
static void exgcd(LL a, LL b, LL &g, LL &x, LL &y) {
if (!b) x = 1, y = 0, g = a;
else {
exgcd(b, a % b, g, y, x);
y -= x * (a / b);
}
}
static LL crt(const vec &c, const vec &m) {
int n = c.size();
LL M = 1, ans = 0;
for (int i = 0; i < n; ++i) M *= m[i];
for (int i = 0; i < n; ++i) {
LL x, y, g, tm = M / m[i];
exgcd(tm, m[i], g, x, y);
ans = (ans + tm * x * c[i] % M) % M;
}
return (ans + M) % M;
}
static vec ReedsSloane(const vec &s, LL mod) {
auto inverse = [](LL a, LL m) {
LL d, x, y;
exgcd(a, m, d, x, y);
return d == 1 ? (x % m + m) % m : -1;
};
auto L = [](const vec &a, const vec &b) {
int da = (a.size() > 1 || (a.size() == 1 && a[0])) ? a.size() - 1 : -1000;
int db = (b.size() > 1 || (b.size() == 1 && b[0])) ? b.size() - 1 : -1000;
return std::max(da, db + 1);
};
auto prime_power = [&](const vec &s, LL mod, LL p, LL e) {
// linear feedback shift register mod p^e, p is prime
std::vector<vec> a(e), b(e), an(e), bn(e), ao(e), bo(e);
vec t(e), u(e), r(e), to(e, 1), uo(e), pw(e + 1);
pw[0] = 1;
for (int i = pw[0] = 1; i <= e; ++i) pw[i] = pw[i - 1] * p;
for (LL i = 0; i < e; ++i) {
a[i] = {pw[i]}, an[i] = {pw[i]};
b[i] = {0}, bn[i] = {s[0] * pw[i] % mod};
t[i] = s[0] * pw[i] % mod;
if (t[i] == 0)
t[i] = 1, u[i] = e;
else
for (u[i] = 0; t[i] % p == 0; t[i] /= p, ++u[i]);
}
for (size_t k = 1; k < s.size(); ++k) {
for (int g = 0; g < e; ++g)
if (L(an[g], bn[g]) > L(a[g], b[g])) {
ao[g] = a[e - 1 - u[g]];
bo[g] = b[e - 1 - u[g]];
to[g] = t[e - 1 - u[g]];
uo[g] = u[e - 1 - u[g]];
r[g] = k - 1;
}
a = an, b = bn;
for (int o = 0; o < e; ++o) {
LL d = 0;
for (size_t i = 0; i < a[o].size() && i <= k; ++i) {
d = (d + a[o][i] * s[k - i]) % mod;
}
if (d == 0) {
t[o] = 1, u[o] = e;
} else {
for (u[o] = 0, t[o] = d; t[o] % p == 0; t[o] /= p, ++u[o]);
int g = e - 1 - u[o];
if (L(a[g], b[g]) == 0) {
extand(bn[o], k + 1);
bn[o][k] = (bn[o][k] + d) % mod;
} else {
LL coef =t[o] * inverse(to[g], mod) % mod * pw[u[o] - uo[g]] % mod;
int m = k - r[g];
extand(an[o], ao[g].size() + m);
extand(bn[o], bo[g].size() + m);
for (size_t i = 0; i < ao[g].size(); ++i) {
an[o][i + m] -= coef * ao[g][i] % mod;
if (an[o][i + m] < 0) an[o][i + m] += mod;
}
while (an[o].size() && an[o].back() == 0) an[o].pop_back();
for (size_t i = 0; i < bo[g].size(); ++i) {
bn[o][i + m] -= coef * bo[g][i] % mod;
if (bn[o][i + m] < 0) bn[o][i + m] -= mod;
}
while (bn[o].size() && bn[o].back() == 0) bn[o].pop_back();
}
}
}
}
return std::make_pair(an[0], bn[0]);
};
std::vector<std::tuple<LL, LL, int>> fac;
for (LL i = 2; i * i <= mod; ++i)
if (mod % i == 0) {
LL cnt = 0, pw = 1;
while (mod % i == 0) mod /= i, ++cnt, pw *= i;
fac.emplace_back(pw, i, cnt);
}
if (mod > 1) fac.emplace_back(mod, mod, 1);
std::vector<vec> as;
size_t n = 0;
for (auto &&x: fac) {
LL mod, p, e;
vec a, b;
std::tie(mod, p, e) = x;
auto ss = s;
for (auto &&x: ss) x %= mod;
std::tie(a, b) = prime_power(ss, mod, p, e);
as.emplace_back(a);
n = std::max(n, a.size());
}
vec a(n), c(as.size()), m(as.size());
for (size_t i = 0; i < n; ++i) {
for (size_t j = 0; j < as.size(); ++j) {
m[j] = std::get<0>(fac[j]);
c[j] = i < as[j].size() ? as[j][i] : 0;
}
a[i] = crt(c, m);
}
return a;
}
LinearRecurrence(const vec &s, const vec &c, LL mod) :
init(s), trans(c), mod(mod), m(s.size()) {}
LinearRecurrence(const vec &s, LL mod, bool is_prime = true) : mod(mod) {
vec A;
A = ReedsSloane(s, mod);
if (A.empty()) A = {0};
m = A.size() - 1;
trans.resize(m);
for (int i = 0; i < m; ++i) trans[i] = (mod - A[i + 1]) % mod;
std::reverse(trans.begin(), trans.end());
init = {s.begin(), s.begin() + m};
}
LL calc(LL n) {
if (mod == 1) return 0;
if (n < m) return init[n];
vec v(m), u(m << 1);
int msk = !!n;
for (LL m = n; m > 1; m >>= 1) msk <<= 1;
v[0] = 1 % mod;
for (int x = 0; msk; msk >>= 1, x <<= 1) {
std::fill_n(u.begin(), m * 2, 0);
x |= !!(n & msk);
if (x < m) u[x] = 1 % mod;
else {// can be optimized by fft/ntt
for (int i = 0; i < m; ++i)
for (int j = 0, t = i + (x & 1); j < m; ++j, ++t)
u[t] = (u[t] + v[i] * v[j]) % mod;
for (int i = m * 2 - 1; i >= m; --i)
for (int j = 0, t = i - m; j < m; ++j, ++t)
u[t] = (u[t] + trans[j] * u[i]) % mod;
}
v = {u.begin(), u.begin() + m};
}
LL ret = 0;
for (int i = 0; i < m; ++i) ret = (ret + v[i] * init[i]) % mod;
return ret;
}
vec init, trans;
LL mod;
int m;
};
int quick_pow(int a,int b)
{
int ans=1;
while(b)
{
if(b&1) ans=1LL*a*ans%mod;
a=1LL*a*a%mod;
b>>=1;
}
return ans;
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
vector<LL> f;
f.push_back(0),f.push_back(1);
for(int i=2;i<=2000;i++)
{
f.push_back((f[i-1]+f[i-2])%mod);
}
for(int i=1;i<=2000;i++) f[i]=quick_pow(f[i],m);
for(int i=1;i<=2000;i++) f[i]=(f[i]+f[i-1])%mod;
LinearRecurrence qw(f,mod,false);
printf("%lld\n",qw.calc(n));
}
用于求解满足不等式组 A X ≥ B AX\ge B AX≥B的 m i n ( C X ) min(CX) min(CX)
当求满足条件的最大的CX时,须对A矩阵进行转置,并对BC进行转置并交换
namespace LP{
const int INF=0x3f3f3f3f;
const int N=505;
const int M=30000;
const double eps=1e-6;
int n,m;
double a[N][M],b[N],c[M],v;
void init(int _n,int _m){n=_n,m=_m;v=0;}
void builda(int i,int j,int val){a[i][j]=val;}
void buildb(int i,int val){b[i]=val;}
void buildc(int i,int val){c[i]=val;}
inline void pivot(int l,int e)//矩阵的转秩
{
b[l]/=a[l][e];
for(int j=1;j<=n;++j)
{
if(j!=e) a[l][j]/=a[l][e];
}
a[l][e]=1/a[l][e];
for(int i=1;i<=m;++i)
{
if(i!=l&&fabs(a[i][e])>0)
{
b[i]-=a[i][e]*b[l];
for(int j=1;j<=n;++j)
{
if(j!=e) a[i][j]-=a[i][e]*a[l][j];
}
a[i][e]=-a[i][e]*a[l][e];
}
}
v+=c[e]*b[l];
for(int j=1;j<=n;++j)
{
if(j!=e) c[j]-=c[e]*a[l][j];
}
c[e]=-c[e]*a[l][e];
}
inline double simplex()
{
while(1)
{
int e=0,l=0;
for(e=1;e<=n;++e)
{
if(c[e]>eps) break;
}
if(e==n+1) return v;
double mn=INF;
for(int i=1;i<=m;++i)
{
if(a[i][e]>eps&&mn>b[i]/a[i][e]) mn=b[i]/a[i][e],l=i;
}
if(mn==INF) return INF;
pivot(l,e);
}
}
}
∑ i = 1 n = ( 1 + n ) n 2 \sum_{i=1}^n=\frac{(1+n)n}{2} i=1∑n=2(1+n)n
2.
∑ i = 1 n i 2 = n ( n + 1 ) ( 2 n + 1 ) 6 \sum_{i=1}^ni^2=\frac{n(n+1)(2n+1)}{6} i=1∑ni2=6n(n+1)(2n+1)
3.
∑ i = 1 n i 3 = ( n ( n + 1 ) 2 ) 2 \sum_{i=1}^ni^3=(\frac{n(n+1)}{2})^2 i=1∑ni3=(2n(n+1))2
#include
using namespace std;
typedef long long LL;
const int maxn=2005;
const int maxm=5e6+5;
const LL inf=1e12;
struct Edge{
int to,nxt;
LL cap,flow;
}edge[maxm];
int tol;
int head[maxn];
inline void init(){
tol=2;
memset(head,-1,sizeof(head));
}
inline void AddEdge(int u,int v,LL w,int rw=0){
edge[tol].to=v;edge[tol].cap=w;edge[tol].flow=0;
edge[tol].nxt=head[u];head[u]=tol++;
edge[tol].to=u;edge[tol].cap=rw;edge[tol].flow=0;
edge[tol].nxt=head[v];head[v]=tol++;
}
int Q[maxn];
int dep[maxn],cur[maxn],sta[maxn];
inline bool bfs(int s,int t,int n){
int front=0,tail=0;
memset(dep,-1,sizeof(dep[0])*(n+1));
dep[s]=0;
Q[tail++]=s;
while(front<tail){
int u=Q[front++];
for(register int i=head[u];i!=-1;i=edge[i].nxt){
int v=edge[i].to;
if(edge[i].cap>edge[i].flow&&dep[v]==-1){
dep[v]=dep[u]+1;
if(v==t) return true;
Q[tail++]=v;
}
}
}
return false;
}
inline LL dinic(int s,int t,int n){
LL maxflow=0;
while(bfs(s,t,n)){
for(register int i=0;i<n;++i) cur[i]=head[i];
int u=s,tail=0;
while(cur[s]!=-1){
if(u==t){
LL tp=inf;
for(register int i=tail-1;i>=0;--i)
{
tp=min(tp,edge[sta[i]].cap-edge[sta[i]].flow);
}
maxflow+=tp;
for(register int i=tail-1;i>=0;--i){
edge[sta[i]].flow+=tp;
edge[sta[i]^1].flow-=tp;
if(edge[sta[i]].cap-edge[sta[i]].flow==0) tail=i;
}
u=edge[sta[tail]^1].to;
}
else if(cur[u]!=-1&&edge[cur[u]].cap>edge[cur[u]].flow&&dep[u]+1==dep[edge[cur[u]].to]){
sta[tail++]=cur[u];
u=edge[cur[u]].to;
}
else{
while(u!=s&&cur[u]==-1) u=edge[sta[--tail]^1].to;
cur[u] = edge [cur[u]].nxt;
}
}
}
return maxflow;
}
#include
using namespace std;
typedef long long LL;
const int maxn=4005;
const int maxm=5e4+4;
const LL inf=1LL<<60;
const LL infc=2e11;
struct Edge{
int to,next,flow,cost;
LL cap;
}edge[maxm];
int head[maxn],tol;
int pre[maxn];LL dis[maxn];
bool vis[maxn];
int N;
void init(int n)
{
N=n;
tol=0;
memset(head,-1,sizeof(head));
}
void AddEdge(int u,int v,LL cap,int cost){
edge[tol].to=v;
edge[tol].cap=cap;
edge[tol].cost=cost;
edge[tol].flow=0;
edge[tol].next=head[u];
head[u]=tol++;
edge[tol].to=u;
edge[tol].cap=0;
edge[tol].cost=-cost;
edge[tol].flow=0;
edge[tol].next=head[v];
head[v]=tol++;
}
bool spfa(int s,int t)
{
queue<int> q;
for(int i=0;i<=N;i++)
{
dis[i]=inf;
vis[i]=false;
pre[i]=-1;
}
dis[s]=0;
vis[s]=true;
q.push(s);
while(!q.empty())
{
int u=q.front();
q.pop();
vis[u]=false;
for(int i=head[u];i!=-1;i=edge[i].next){
int v=edge[i].to;
if(edge[i].cap>edge[i].flow&&dis[v]>dis[u]+edge[i].cost)
{
dis[v]=dis[u]+edge[i].cost;
pre[v]=i;
if(!vis[v]){
vis[v]=true;
q.push(v);
}
}
}
}
if(pre[t]==-1) return false;
else return true;
}
int MincostMaxflow(int s,int t,LL &cost){
LL flow=0;
cost=0;
while(spfa(s,t)){
LL Min=inf;
for(int i=pre[t];i!=-1;i=pre[edge[i^1].to]){
if(Min>edge[i].cap-edge[i].flow)
Min=edge[i].cap-edge[i].flow;
}
for(int i=pre[t];i!=-1;i=pre[edge[i^1].to]){
edge[i].flow+=Min;
edge[i^1].flow-=Min;
cost+=1LL*edge[i].cost*Min;
}
flow+=Min;
}
return flow;
}
#include
#include
#include
#include
#include
#include
#include
using namespace std;
int n, m, S, T, slk[1001], dist[1001], first[1001], l, c[1000001], next[1000001], where[1000001], ll[1000001], v[1000001];
bool b[1001];
long long ans1, ans2;
inline void makelist(int x, int y, int z, int p){
where[++l] = y;
ll[l] = z;
v[l] = p;
next[l] = first[x];
first[x] = l;
}
inline void spfa(){
memset(dist, 127, sizeof(dist));
memset(b, false, sizeof(b));
dist[T] = 0; c[1] = T;
for (int k = 1, l = 1; l <= k; l++)
{
int m = c[l];
b[m] = false;
for (int x = first[m]; x; x = next[x])
if (ll[x ^ 1] && dist[m] - v[x] < dist[where[x]])
{
dist[where[x]] = dist[m] - v[x];
if (!b[where[x]]) b[where[x]] = true, c[++k] = where[x];
}
}
}
int zkw_work(int now, int cap){
b[now] = true;
if (now == T)
{
ans1 += cap;
ans2 += (long long)cap * dist[S];
return(cap);
}
int Left = cap;
for (int x = first[now]; x; x = next[x])
if (ll[x] && !b[where[x]])
if (dist[now] == dist[where[x]] + v[x])
{
int use = zkw_work(where[x], min(Left, ll[x]));
ll[x] -= use; ll[x ^ 1] += use;
Left -= use;
if (!Left) return(cap);
}
else slk[where[x]] = min(slk[where[x]], dist[where[x]] + v[x] - dist[now]);
return(cap - Left);
}
bool relax(){
int Min = 1 << 30;
for (int i = 0; i <= T; i++)
if (!b[i]) Min = min(Min, slk[i]);
if (Min == 1 << 30) return(false);
for (int i = 0; i <= T; i++)
if (b[i]) dist[i] += Min;
return(true);
}
inline void zkw(){
ans1 = ans2 = 0;
spfa(); //hint memset(dist, 0, sizeof(dist)); if all values of edges are nonnegative
for (;;)
{
memset(slk, 127, sizeof(slk));
for (;;)
{
memset(b, false, sizeof(b));
if (!zkw_work(S, 1 << 30)) break;
}
if (!relax()) break;
}
printf("%I64d %I64d\n", ans1, ans2);
}
int main(){
scanf("%d%d", &n, &m);
S = 1; T = n;
memset(first, 0, sizeof(first)); l = 1;
for (int i = 1; i <= m; i++)
{
int x, y, z, q;
scanf("%d%d%d%d", &x, &y, &z, &q);
makelist(x, y, z, q); makelist(y, x, 0, -q);
}
zkw();
}
#include
using namespace std;
typedef pair<int, int> pii;
const int maxn = 1e4;
const int inf = 0x3f3f3f3f;
struct edge {
int to, cap, cost, rev;
edge() {}
edge(int to, int _cap, int _cost, int _rev) :to(to), cap(_cap), cost(_cost), rev(_rev) {}
};
int V, H[maxn + 5], dis[maxn + 5], PreV[maxn + 5], PreE[maxn + 5];
vector<edge> G[maxn + 5];
void init(int n) {
V = n;
for (int i = 0; i <= V; ++i)G[i].clear();
}
void AddEdge(int from, int to, int cap, int cost) {
G[from].push_back(edge(to, cap, cost, G[to].size()));
G[to].push_back(edge(from, 0, -cost, G[from].size() - 1));
}
int Min_cost_max_flow(int s, int t, int f, int& flow) {
int res = 0; fill(H, H + 1 + V, 0);
while (f) {
priority_queue <pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>> > q;
fill(dis, dis + 1 + V, inf);
dis[s] = 0; q.push(pair<int, int>(0, s));
while (!q.empty()) {
pair<int, int> now = q.top(); q.pop();
int v = now.second;
if (dis[v] < now.first)continue;
for (int i = 0; i < G[v].size(); ++i) {
edge& e = G[v][i];
if (e.cap > 0 && dis[e.to] > dis[v] + e.cost + H[v] - H[e.to]) {
dis[e.to] = dis[v] + e.cost + H[v] - H[e.to];
PreV[e.to] = v;
PreE[e.to] = i;
q.push(pair<int, int>(dis[e.to], e.to));
}
}
}
if (dis[t] == inf)break;
for (int i = 0; i <= V; ++i)H[i] += dis[i];
int d = f;
for (int v = t; v != s; v = PreV[v])d = min(d, G[PreV[v]][PreE[v]].cap);
f -= d; flow += d; res += d*H[t];
for (int v = t; v != s; v = PreV[v]) {
edge& e = G[PreV[v]][PreE[v]];
e.cap -= d;
G[v][e.rev].cap += d;
}
}
return res;
}
int a[maxn];
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int n,k;
scanf("%d%d",&n,&k);
for(register int i=1;i<=n;++i) scanf("%d",&a[i]);
int ss=0,s=1,t=2*n+2,tt=2*n+3;
init(tt+1);
AddEdge(ss,s,k,0);
AddEdge(t,tt,k,0);
for(register int i=1;i<=n;++i)
{
AddEdge(s,i+1,1,0);
AddEdge(i+1+n,t,1,0);
AddEdge(i+1,i+1+n,1,-a[i]);
for(register int j=i+1;j<=n;++j)
{
if(a[j]>=a[i])
{
AddEdge(1+i+n,1+j,1,0);
}
}
}
int ans=0;
printf("%d\n",-Min_cost_max_flow(ss,tt,inf,ans));
}
return 0;
}
Q:给出一幅图,对其中的点进行黑白染色,边根据两个端点的颜色不同有不同的权值,设为A,B,C,问如何染色使得总的边权最大
A:设一个源点一个汇点,其中xy都是原图的点,建下述图,通过作割表示不选择其他两种方案
这样就要求有
a + b = B + A c + d = C + B a + e + d = A + C b + e + c = A + C \begin{aligned} a+b&=B+A\\ c+d&=C+B\\ a+e+d&=A+C\\ b+e+c&=A+C \end{aligned} a+bc+da+e+db+e+c=B+A=C+B=A+C=A+C
可以得到一组解 a = b = ( A + B ) / 2 , c = d = ( C + B ) / 2 , e = − B + ( A + C ) / 2 a=b=(A+B)/2,c=d=(C+B)/2,e=-B+(A+C)/2 a=b=(A+B)/2,c=d=(C+B)/2,e=−B+(A+C)/2
用所有的贡献减去这个的最小割就是答案
Q:求二分图的最大独立集
A: 对于二分图(U, V) 源连向U,V连向汇。跑完网络流后,残余网络上,从源可达的U中的点,和从源不可达的V中的点,加起来就是最大独立集了
Q:给出一幅图,对其中的点进行黑白染色,染不同的颜色有不同的收益,其中如果有一些点(称为一个组)染相同的颜色就会额外获得一些收益,问收益最大
A:设立一个源点一个汇点,源点向所有的点连接容量为白色时的收益,所有的点向汇点连接容量为黑色时的收益,对所有的组的不同颜色设立虚点,源点向全组为白色时的组的虚点连接组为白色时的收益,全组为黑色时的组的虚点向汇点连边。最终,总的收益减去这幅图的最小割就是答案
Q:给出一幅图,请割出其字典序最小的最小割
A: 对所有可能被割的边对字典序从小到大bfs作连通性检查,如果不联通则是最小割边集中的边,接下来对这条边向终点的跑一边dinic退流,这条边向源点跑一遍dinic退流,最后把这条边和其反向边容量置0,则这条边就会被从原本图中删去,接下来继续检测字典序更大的边即可,代码实现见后面的“字典序最小割”
Q:给出一幅图,求最大权闭合子图
A:将原图中的所有边照原状连接,容量无穷大,从源点向所有权值为正的点连边,所有权值为负的点向汇点连接边,容量均为点的权值的绝对值。最大权闭合子图的最大权值就是所有正权点的权值和减去这幅图的最小割
Q:给出一幅图,需要满足所有的边的容量介于上下界之间,求可行流
A:对于一副循环图(即无源点和汇点,起始点和终末点之间存在一条容量无限大的边)来说,假设其中的每条边的流量都介于[l,r]直接,我们不妨将l取出,将原边变为[0,r-l],与一条容量为l的必行边,并在这条边中间插入两个点,设为x,y,细节见图示
我们不难发现从x到y的流量只有x->y一条,因此其x->y的最大流也就是3,于是我们可以据此推理出假使存在一条从y到x的最大流等于3时就是所有的必行边都被走过了,那么这个图就是可行的。
但是本题是一个有汇源点的图,所以我们要想办法将之转化为循环图,具体方法就是在汇点和源点直接也连上一条无穷大的边即可。需要注意的是:
从汇点向源点连!
Dijkstra
//Dijkstra
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define int long long
#define endl '\n'
#define sc(x) scanf("%lld",&x)
using namespace std;
const int size=105;
const int inf=0x3f3f3f3f;
struct Edge{
int u,v,w;
Edge(int u=0,int v=0,int w=0):u(u),v(v),w(w){}
};
struct node{
int id,w;
node(int id=0,int w=0):id(id),w(w){}
friend bool operator<(node a,node b)
{
return a.w>b.w;
}
};
priority_queue<node> q;
vector<Edge> edge[size];
int dis[size],vis[size];
void Dijkstra(int beg)
{
memset(dis,inf,sizeof(dis));
memset(vis,0,sizeof(vis));
while(!q.empty()) q.pop();
q.push(node(beg,0)),dis[beg]=0;
while(!q.empty())
{
node s=q.top();
q.pop();
int id=s.id;
if(dis[id]!=s.w) continue;
for(int i=0;i<edge[id].size();i++)
{
if(dis[edge[id][i].v]>dis[id]+edge[id][i].w)
{
dis[edge[id][i].v]=dis[id]+edge[id][i].w;
q.push(node(edge[id][i].v,dis[edge[id][i].v]));
}
}
}
}
int32_t main()
{
int n,m;
while(cin>>n>>m&&n)
{
int i,u,v,w<