目录
一 polya定理,Burnside引理
转自:https://blog.csdn.net/whereisherofrom/article/details/79631703
1.Burnside引理:
L代表m种颜色给n个对象染色的总方案数,|G|代表置换个数,|D(gi)|代表在gi这种置换作用下没有改变状态的方案个数。
2,polya定理:
m种颜色给n个对象染色的方案数如图所示。G代表变换(置换)的种类,其中Ci代表每种置换下的循环节。
二 拉格朗日插值法
参考博客:https://www.luogu.org/problemnew/solution/P4781
/*
n+1个点可以确定一个n次多项式,给定n+1个点,求这个多项式的第k项
fast_mod 快速幂 inv 逆元 X[],Y[] 点的坐标
*/
ll calc(ll k) {
ll ans = 0;
for (int i = 0; i < n; i++) {
ll s = Y[i]%mod,s1=1LL;
for (int j = 0; j < n; j++) {
if (i != j)s = s * (k - X[j]) % mod,s1=s1*((X[i]-X[j])%mod)%mod;
}
ans = (ans + s * inv(s1) % mod)%mod;
ans = (ans + mod) % mod;
}
return ans;
}
若x是连续的,则可以O(n)求解:
int lagrange(int n, int *x, int *y, int xi) {
int ans = 0;
s1[0] = (xi-x[0])%mod, s2[n+1] = 1;
for (int i = 1; i <= n; i++) s1[i] = 1ll*s1[i-1]*(xi-x[i])%mod;
for (int i = n; i >= 0; i--) s2[i] = 1ll*s2[i+1]*(xi-x[i])%mod;
ifac[0] = ifac[1] = 1;
for (int i = 2; i <= n; i++) ifac[i] = -1ll*mod/i*ifac[mod%i]%mod;
for (int i = 2; i <= n; i++) ifac[i] = 1ll*ifac[i]*ifac[i-1]%mod;
for (int i = 0; i <= n; i++)
(ans += 1ll*y[i]*(i == 0 ? 1 : s1[i-1])%mod*s2[i+1]%mod
*ifac[i]%mod*(((n-i)&1) ? -1 : 1)*ifac[n-i]%mod) %= mod;
return (ans+mod)%mod;
}
struct lagrange {
#define D 1100
//D比MAXN大100就行
ll a[D], f[D], g[D], p[D], p1[D], p2[D], b[D], h[D][2], C[D];
void init(int M) {//初始化:参数填MAXN + 20
f[0] = f[1] = g[0] = g[1] = 1;
for(int i=2;i<M+5;i++)f[i] = f[i - 1] * i % mod;
g[M + 4] = powmod(f[M + 4], mod - 2);
for(int i=M+3;i>=1;i--)g[i] = g[i + 1] * (i + 1) % mod;
}
/*给定一组样本数据a[],规模为0-d,计算出第n项*/
ll calcn(int d, ll *a, ll n) {
if (n <= d) return a[n];
p1[0] = p2[0] = 1;
for(int i=0;i<d+1;i++){
ll t = (n - i + mod) % mod;
p1[i + 1] = p1[i] * t % mod;
}
for(int i=0;i<d+1;i++){
ll t = (n - d + i + mod) % mod;
p2[i + 1] = p2[i] * t % mod;
}
ll ans = 0;
for(int i=0;i<=d;i++){
ll t = g[i] * g[d - i] % mod * p1[i] % mod * p2[d - i] % mod * a[i] % mod;
if ((d - i) & 1) ans = (ans - t + mod) % mod;
else ans = (ans + t) % mod;
}
return ans;
}
/*
给定一组观测点(0, a[0]), (1, a[1]), ...,(m, a[m]),、
样本点的个数为a(x)的最高次+1。
求在该函数模型下,a[0]+a[1]+...+a[n]的和。
*/
ll ta[D];
ll polysum(ll m, ll *a, ll n) { // 给定a[0].. a[m],求\sum_{i=0}^{n}a[i]
memcpy(ta, a, sizeof(a[0]) * (m + 1));
ta[m + 1] = calcn(m, ta, m + 1);
for(int i=1;i<m+2;i++)ta[i] = (ta[i - 1] + ta[i]) % mod;
return calcn(m + 1, ta, n);
}
};
三 线性齐次递推(需要前2×k项)
typedef long long ll;
typedef long double ld;
typedef pair<int, int> P;
#define pu push
#define pb push_back
#define pf push_front
#define mp make_pair
#define fi first
#define SZ(x) (int)x.size()
#define se second
#define rep(i, a, b) for (int i = (a); i < (b); i++)
#define per(i, a, b) for (int i = (a); i >= (b); i--)
#define repn(i, a, b) for (int i = (a); i <= (b); i++)
#define repv(i, v) for (auto i : v)
const int dir[4][2] = {1, 0, 0, 1, -1, 0, 0, -1};
const int eps = 1e-7;
const int inf = 0x3f3f3f3f;
const int mod = 1000000007;
const int maxn = 1e2;
typedef vector<ll> VI;
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;
}
// head
int _, n;
namespace linear_seq {
const int N=10010;
ll res[N],base[N],_c[N],_md[N];
vector<int> Md;
inline void mul(ll *a,ll *b,int k) {
for(int i=0;i<k+k;i++) _c[i]=0;
for(int i=0;i<k;i++) if (a[i]) for(int j=0;j<k;j++) _c[i+j]=(_c[i+j]+a[i]*b[j])%mod;
for (int i=k+k-1;i>=k;i--) if (_c[i])
for(int j=0;j<Md.size();j++) _c[i-k+Md[j]]=(_c[i-k+Md[j]]-_c[i]*_md[Md[j]])%mod;
for(int i=0;i<k;i++) a[i]=_c[i];
}
inline int solve(ll n,VI a,VI b) { // a 系数 b 初值 b[n+1]=a[0]*b[n]+...
ll ans=0,pnt=0;
int k=SZ(a);
assert(SZ(a)==SZ(b));
for(int i=0;i<k;i++) _md[k-1-i]=-a[i];_md[k]=1;
Md.clear();
for(int i=0;i<k;i++) 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;
for(int j=0;j<Md.size();j++) res[Md[j]]=(res[Md[j]]-res[k]*_md[Md[j]])%mod;
}
}
for(int i=0;i<k;i++) ans=(ans+res[i]*b[i])%mod;
if (ans<0) ans+=mod;
return ans;
}
inline VI BM(VI s) {
VI C(1,1),B(1,1);
int L=0,m=1,b=1;
for(int n=0;n<s.size();n++) {
ll d=0;
for(int i=0;i<L+1;i++) 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);
for(int i=0;i<B.size();i++) 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);
for(int i=0;i<B.size();i++) C[i+m]=(C[i+m]+c*B[i])%mod;
++m;
}
}
return C;
}
inline int gao(VI a,ll n) { //前2×k项,以及要求的第n项,返回结果;VI 是vector;
VI c=BM(a);
c.erase(c.begin());
for(int i=0;i<c.size();i++) c[i]=(mod-c[i])%mod;
return solve(n,c,VI(a.begin(),a.begin()+SZ(c)));
}
};
三 线性基(交集)
struct Line_base {
ll b[M];
Line_base (){
memset(b,0,sizeof(b));
}
void Insert(ll x) {
for (int i = 33; i >= 0; i--) {
if (x&(1LL << i)) {
if (b[i])x ^= b[i];
else {
b[i] = x;
break;
}
}
}
}
bool check(ll x) {
for (int i = 33; i >= 0; i--) {
if (x&(1LL << i)) {
if (!b[i])return false;
else x ^= b[i];
}
}
return true;
}
//交集
friend Line_base operator + (const Line_base &a, const Line_base &b){
Line_base ans , c = b, d = b;
for(int i=0;i< 34;i++)
{
ll x = a.b[i];
if (!x)continue;
int j = i; ll T = 0;
for (; j >= 0; --j)
if ((x >> j) & 1)
if (c.b[j]) { x ^= c.b[j]; T ^= d.b[j]; }
else break;
if (!x)ans.b[i] = T;
else { c.b[j] = x; d.b[j] = T; }
}
return ans;
}
};
四 Lucas定理(组合数)
#define ll long long
const int N = 1e5 + 10;
ll mod, n, m;
ll fac[N];
void init() {
fac[0] = 1;
for (int i = 1; i <= mod; i++) fac[i] = fac[i - 1] * i%mod;
}
/*
C(n,m)%p=C(n/p,m/p)*C(n%p,m%p)%p 卢卡斯定理,模数不能太大,n,m可以大
*/
ll quik(ll x,ll n) {
ll ans = 1;
while (n) {
if (n & 1)ans = ans * x%mod;
n >>= 1;
x = x * x%mod;
}
return ans;
}
ll C(ll n, ll m) {
if (m > n)return 0;
return fac[n] * quik(fac[m] * fac[n - m] % mod, mod - 2) % mod;
}
ll Lucas(ll n, ll m) {
if (m == 0)return 1;
return C(n%mod, m%mod)*Lucas(n / mod, m / mod) % mod;
}
五 Pollard's Rho算法(大数质因数分解)
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<queue>
using namespace std;
typedef long long ll;
const int maxn = 105;
ll x[maxn], ans;
queue<ll> aria;
ll min(ll a, ll b)
{
if (a < b) return a;
else return b;
}
ll multi(ll a, ll b, ll p) //快速乘?
{
ll ans = 0;
while (b) {
if (b & 1LL) ans = (ans + a) % p;
a = (a + a) % p;
b >>= 1;
}
return ans;
}
ll qpow(ll a, ll b, ll p)
{
ll ans = 1;
while (b) {
if (b & 1LL) ans = multi(ans, a, p);
a = multi(a, a, p);
b >>= 1;
}
return ans;
}
bool MR(ll n)
{
if (n == 2) return true;
int s = 20, i, t = 0;
ll u = n - 1;
while (!(u & 1)) {
t++;
u >>= 1;
}
while (s--) {
ll a = rand() % (n - 2) + 2;
x[0] = qpow(a, u, n);
for (i = 1; i <= t; i++) {
x[i] = multi(x[i - 1], x[i - 1], n);
if (x[i] == 1 && x[i - 1] != 1 && x[i - 1] != n - 1) return false;
}
if (x[t] != 1) return false;
}
return true;
}
ll gcd(ll a, ll b)
{
if (b == 0) return a;
else return gcd(b, a%b);
}
ll Pollard_Rho(ll n, int c)
{
ll i = 1, k = 2, x = rand() % (n - 1) + 1, y = x;
while (1) {
i++;
x = (multi(x, x, n) + c) % n;
ll p = gcd((y - x + n) % n, n);
if (p != 1 && p != n) return p;
if (y == x) return n;
if (i == k) {
y = x;
k <<= 1;
}
}
}
void find(ll n, int c)
{
if (n == 1) return;
if (MR(n)) {
aria.push(n);
return;
}
ll p = n, k = c;
while (p >= n) {
p = Pollard_Rho(p, c--);
}
find(p, k);
find(n / p, k);
}
int main()
{
ll n;
while (~scanf("%lld", &n)) {
find(n, 107);
cout << aria.front();
aria.pop();
while (!aria.empty()) {
cout << "*" << aria.front();
aria.pop();
}
cout << endl;
}
return 0;
}
六 二次剩余
#define ll long long
const ll p = 1e9 + 7;
ll w;
struct T { ll x, y; };
T mul_two(T a, T b, ll p) {
T ans;
ans.x = (a.x*b.x%p + a.y*b.y%p*w%p) % p;
ans.y = (a.x*b.y%p + a.y*b.x%p) % p;
return ans;
}
T qpow_two(T a, ll n, ll p) {
T ans;
ans.x = 1;
ans.y = 0;
while (n) {
if (n & 1) ans = mul_two(ans, a, p);
n >>= 1;
a = mul_two(a, a, p);
}
return ans;
}
ll qpow(ll a, ll n, ll p) {
ll ans = 1;
a %= p;
while (n) {
if (n & 1) ans = ans * a%p;
n >>= 1;
a = a * a%p;
}
return ans % p;
}
ll Legendre(ll a, ll p) {
return qpow(a, (p - 1) >> 1, p);
}
ll solve(ll n, ll p) {
if (n == 0) return 0;
if (n == 1) return 1;
if (Legendre(n, p) + 1 == p) return -1;
ll a, t;
while (1) {
a = rand() % p;
t = a * a - n;
w = (t%p + p) % p;
if (Legendre(w, p) + 1 == p) break;
}
T tmp;
tmp.x = a;
tmp.y = 1;
T ans = qpow_two(tmp, (p + 1) >> 1, p);
return ans.x;
}
七 多边形求交
//点按顺时针或者逆时针给出
#include<bits/stdc++.h>
using namespace std;
#define maxn 510
const double eps = 1E-8;
int sig(double d) {
return(d > eps) - (d < -eps);
}
struct Point {
double x, y; Point() {}
Point(double x, double y) :x(x), y(y) {}
bool operator==(const Point&p)const {
return sig(x - p.x) == 0 && sig(y - p.y) == 0;
}
};
double cross(Point o, Point a, Point b) {
return(a.x - o.x)*(b.y - o.y) - (b.x - o.x)*(a.y - o.y);
}
double area(Point* ps, int n) {
ps[n] = ps[0];
double res = 0;
for (int i = 0; i < n; i++) {
res += ps[i].x*ps[i + 1].y - ps[i].y*ps[i + 1].x;
}
return res / 2.0;
}
int lineCross(Point a, Point b, Point c, Point d, Point&p) {
double s1, s2;
s1 = cross(a, b, c);
s2 = cross(a, b, d);
if (sig(s1) == 0 && sig(s2) == 0) return 2;
if (sig(s2 - s1) == 0) return 0;
p.x = (c.x*s2 - d.x*s1) / (s2 - s1);
p.y = (c.y*s2 - d.y*s1) / (s2 - s1);
return 1;
}
//多边形切割
//用直线ab切割多边形p,切割后的在向量(a,b)的左侧,并原地保存切割结果
//如果退化为一个点,也会返回去,此时n为1
void polygon_cut(Point*p, int&n, Point a, Point b) {
static Point pp[maxn];
int m = 0; p[n] = p[0];
for (int i = 0; i < n; i++) {
if (sig(cross(a, b, p[i])) > 0) pp[m++] = p[i];
if (sig(cross(a, b, p[i])) != sig(cross(a, b, p[i + 1])))
lineCross(a, b, p[i], p[i + 1], pp[m++]);
}
n = 0;
for (int i = 0; i < m; i++)
if (!i || !(pp[i] == pp[i - 1]))
p[n++] = pp[i];
while (n > 1 && p[n - 1] == p[0])n--;
}
//---------------华丽的分隔线-----------------//
//返回三角形oab和三角形ocd的有向交面积,o是原点//
double intersectArea(Point a, Point b, Point c, Point d) {
Point o(0, 0);
int s1 = sig(cross(o, a, b));
int s2 = sig(cross(o, c, d));
if (s1 == 0 || s2 == 0)return 0.0;//退化,面积为0
if (s1 == -1) swap(a, b);
if (s2 == -1) swap(c, d);
Point p[10] = { o,a,b };
int n = 3;
polygon_cut(p, n, o, c);
polygon_cut(p, n, c, d);
polygon_cut(p, n, d, o);
double res = fabs(area(p, n));
if (s1*s2 == -1) res = -res; return res;
}
//求两多边形的交面积
double intersectArea(Point*ps1, int n1, Point*ps2, int n2) {
if (area(ps1, n1) < 0) reverse(ps1, ps1 + n1);
if (area(ps2, n2) < 0) reverse(ps2, ps2 + n2);
ps1[n1] = ps1[0];
ps2[n2] = ps2[0];
double res = 0;
for (int i = 0; i < n1; i++) {
for (int j = 0; j < n2; j++) {
res += intersectArea(ps1[i], ps1[i + 1], ps2[j], ps2[j + 1]);
}
}
return res;//assumeresispositive!
}
//hdu-3060求两个任意简单多边形的并面积
Point p1[maxn], p2[maxn];
int a, b, c, d, e, f, g, h;
int main() {
int i;
while (scanf("%d%d%d%d%d%d%d%d", &a, &b, &c, &d, &e, &f, &g, &h) != EOF) {
p1[0].x = a; p1[0].y = b; p1[1].x = a; p1[1].y = d; p1[2].x = c; p1[2].y = b;
p2[0].x = e; p2[0].y = f; p2[1].x = e; p2[1].y = h; p2[2].x = g; p2[2].y = h; p2[3].x = g; p2[3].y = f;
printf("%.8lf\n", intersectArea(p1, 3, p2, 4));
}
return 0;
}
八 两圆面积交
#include <bits/stdc++.h>
using namespace std;
#define Pi acos(-1.0)
using namespace std;
int main(){
double x1,x2,r1,r2,y1,y2;//定义两圆心及半径
while (scanf("%lf%lf%lf%lf%lf%lf",&x1,&y1,&r1,&x2,&y2,&r2)!=EOF){//输入
double x=abs(x1-x2); //求出X差
double y=abs(y1-y2); //求出Y差
double l=sqrt(x*x+y*y); //求和距离
if (r1<r2) swap(r1,r2); //保证R1<R2
if (r1+r2<=l) printf("0.000\n");//两圆分离
else if (abs(r1-r2)>=l) printf("%.3f\n",Pi*min(r1*r1,r2*r2));//包含关系
else {//否则就是相交
double a=r1,b=r2,c=l;//A是半径一,B是半径二
double A=acos((c*c+b*b-a*a)/(2*c*b));//读出圆一的交弧角度
double B=acos((c*c+a*a-b*b)/(2*c*a));//读出圆二的交弧角度
double s=(a+b+c)/2; //求出三角形周长一半
s=sqrt(s*(s-a)*(s-b)*(s-c));//海勒公式求面积,这个三角形是底是圆心距,高是连心线到交点垂线距
double area=a*a*B+b*b*A-2*s;//求出答案
printf("%.3f\n",area); //输出
}//基本思路就是两圆减去两个三角形
}
return 0;
}