小知识杂记(知识点)

杀马特。学长 韩版系。学妹 提交于 2020-03-01 21:56:49

lower_bound()

函数lower_bound()在first和last中的前闭后开区间进行二分查找,返回大于或等于val的第一个元素位置。

调用lower_bound之前必须确定序列为有序序列,否则调用出错。

lower_bound(val): 返回容器中第一个值【大于或等于】val的元素的iterator位置。

upper_bound(val): 返回容器中第一个值【大于】val的元素的iterator位置。

对于有序数组a【n】,lower_bound(a,a+n,x)值为第一个【大于或等于】x的元素在数组中的下标;

hash

对于字符串sh【N】其hash值可以为

for(int i=0;i<n;i++)hash=hash*base+sh[i]   //base是一个小质数 hash的初始值为0;

对于查找字符串sh2中包含几个字符串sh可以进行如下操作

for(int i=0;i<strlen(sh2);i++)hs[i+1]=hs[i]*base+sh2[i];

for(int i=0;i+strlen(sh)-1<strlen(sh2);i++)if(hash==genth(i,i+strlen(sh)))ans++;

//genth(int l,int r){return hs[r+1]-po[r-l+1]*hs[l];}//po[i]表示base的i次方;

 

map

 

定义(在主函数外):map< long long,int>p;//定义了一个从long long类型指向int 类型的映射数组p

赋值(在函数内):p[x]=y;

 

 

typedef/#define

(此部分有部分内容转自http://blog.csdn.net/luoweifu/article/details/41630195)

例用:typedef unsigned long long ull;//和define不一样前面没有#后面要加分号;

#define ll long long   //原件和替件位置也不一样

typedef故名思意就是类型定义的意思,但是它并不是定义一个新的类型而是给已有的类型起一个别名,在这一点上与引用的含义类似,引用是变量或对象的别名,而typedef定义的是类型的别名

关键字typedef在编译阶段有效,由于是在编译阶段,因此typedef有类型检查的功能。

#define则是宏定义,发生在预处理阶段,也就是编译之前,它只进行简单而机械的字符串替换,而不进行任何检查。

#define不只是可以为类型取别名,还可以定义常量、变量、编译开关等。

 

读入优化

不推荐用这种方法

inline char GET_CHAR()

{//读优卡常

    static char buf[maxn],*p1=buf,*p2=buf;

return p1==p2&&(p2=(p1=buf)+fread(buf,1,maxn,stdin),p1==p2)?EOF:*p1++;

}

template<class T>inline void read(T &x){//读优背一下就OK

x=0;int f=0;char ch=GET_CHAR();

while(ch<'0'||ch>'9') {f|=(ch=='-');ch=GET_CHAR();}

while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=GET_CHAR();}

    x=f?-x:x;

}

真。读入优化

#define num ch-'0'

void get(int &res)

{

    char ch;bool flag=0;

    while(!isdigit(ch=getchar()))

        (ch=='-')&&(flag=true);

    for(res=num;isdigit(ch=getchar());res=res*10+num);

        (flag)&&(res=-res);

}

void read(int &x)

{

    int f=1;x=0;char s=getchar();

    while(s<'0'||s>'9')

    {

        if(s=='-')f=-1;

        s=getchar();

    }

    while(s>='0'&&s<='9')

    {

        x=x*10+s-'0';

        s=getchar();

    }

    x*=f;

}

输出优化

void print(int x)//这里当然不用实参

{

    if(x<0)//负数

    {

     putchar('-');

     x=-x;

    }

    if(x>9)//只要x还是2位数或更多就继续分解

        print(x/10);//这里递归完后栈里面x的每一位是倒过来的(关于递归,我也实在解释不清楚,各位去看看神犇们的递归解释吧)

    putchar(x%10+'0');//输出(要把int型变为char型,加'0'即可)
}

线性筛

.

//1-100000的质数 
#include<iostream>
using namespace std;
int pd[100010],m=100010;
int zhishu[100010],n;
int main()
{
    cin>>n;
    pd[0]=1;pd[1]=1;
    for(int i=2;i<=m;i++)
    {
        if(!pd[i])
        zhishu[++zhishu[0]]=i;
        for(int j=1;j<=zhishu[0]&&zhishu[j]*i<m;j++)
        {
            pd[i*zhishu[j]]=1;
            if(i%zhishu[j]==0)
            {
                break;
            }
        }
    }
    for(int i=1;i<=n;i++)
    {
        cout<<zhishu[i]<<"\n";
    }
}

 

快速幂

int ksm(long long a,long long b)

{

    long long ans=1,c=a;

    while(b!=0)

    {

        if(b&1!=0)ans=ans*c%10007;

        c=c*c%10007;

        b>>=1;

    }

    return ans%10007;

}

环涂色公式

有M(m>=2)个区域,如果给你n(n>=3)种颜色,给这m个区域涂色,

要求相邻的区域颜色不能一样,问一共有几种涂法;

公式是:f(m)=(-1)^m*(n-1)+(n-1)^m

n(n-1)^(m-1)表示不考虑1区域和m区域的颜色

由两种情况组成 即同色与不同色

不同色的情况可以将1区域和n区域合成为1区域

n(n-1)^(m-1)=am+am-1---->am=am-1-n(n-1)^(m-1)-->

am-(n-1)^(m)=-(am-1-(n-1)^(m-1))--->(等比数列)

第一类斯特林数(Stirling)

 

 给出恰包含 m 个圈的 n 个元素 的排列数目. 斯特林数满足母函数关系

设S(p,k)是斯特林数

S(p,k)的一个组合学解释是:将p个物体划分成k个非空的不可辨别的(可以理解为盒子没有编号)集合的方法数。

S(p,k)的递推公式是:

 S(p,k) = k*S(p-1,k) + S(p-1,k-1) ,1<= k <=p-1

边界条件:

S(p,p) = 1 ,p>=0

S(p,0) = 0 ,p>=1

递推关系的说明:考虑第p个物品,p可以单独构成一个非空集合,此时前p-1个物品构成k-1个非空的不可辨别的集合,方法数为S(p-1,k-1);也可以前p-1种物品构成k个非空的不可辨别的集合,第p个物品放入任意一个中,这样有k*S(p-1,k)种方法。

void Stirling(int n, int mod)
{
    s[1][0] = 0; s[1][1] = 1;
    for(INT i = 2; i <= n; i ++){
        s[i][0] = 0;
        for(INT j = 1; j < i; j ++)
        s[i][j] = ((i - 1) * s[i - 1][j] + s[i - 1][j - 1]) % mod;
        s[i][i] = 1;
    }
}


 

第二类斯特林数

S(n,k)表示将n个物体划分成k个非空的不可辨别的(可以理解为盒子没有编号)集合的方法

 

定义:

Sn,k是基数为n的集合的划分为k个集合方法的数目。例如S3,2 = 3因为3个元素的集合{a, b, c}有3种不同的划分方法:

{{a}, {b, c}}, {{b}, {a, c}}, {{c}, {a, b}}。可以知道Bell(n) = Sn,ki,( 1 <= ki <= n)。

公式:

递推式:S(n, k) = k * S(n - 1, k) + S(n - 1, k - 1)

              S(n, n) = 1, n >= 0..  S(n, 0) = 0, n >= 1..

解释:第n个物品来单独考虑。。我们要分为k个集合。。

1.可以把当前第n个物品作为一个集合,也就是S(n - 1, k - 1)中方法。

2.也可以把当前第n个物品放在其他的集合中来构成k个集合。也就是S(n - 1, k)中方法。。

 

贝尔数(集合划分问题)

n个元素的集合{1,2,...,n}可以划分若干个非空子集。

设n个元素的集合可以划分为F(n,m)个不同的由m个非空子集组成的集合。

考虑3个元素的集合,可划分为
① 1个子集的集合:{{1,2,3}}
② 2个子集的集合:{{1,2},{3}},{{1,3},{2}},{{2,3},{1}}
③ 3个子集的集合:{{1},{2},{3}}
∴F(3,1)=1;F(3,2)=3;F(3,3)=1;

如果要求F(4,2)该怎么办呢?

A.往①里添一个元素{4},得到{{1,2,3},{4}}

B.往②里的任意一个子集添一个4,得到
{{1,2,4},{3}},{{1,2},{3,4}},
{{1,3,4},{2}},{{1,3},{2,4}},
{{2,3,4},{1}},{{2,3},{1,4}}

∴F(4,2)=F(3,1)+2*F(3,2)=1+2*3=7

推广,得F(n,m)=F(n-1,m-1)+m*F(n-1,m)

Bell数的定义:第n个Bell数表示集合{1,2,3,...,n}的划分方案数,即:B[0] = 1;

每一个Bell数都是第二类Stirling数的和
 

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
long long S(long long m,long long n)
{
    if(m==1)
        return 1;
    if(m==n)
        return 1;
    else
        return S(m-1,n-1)+S(m,n-1)*m;
}
 
int main()
{
    long long n,i;
    while(cin>>n)
    {
        long long sum=0;
        for(i=1; i<=n; i++)
            sum+=S(i,n);
        cout<<sum<<endl;
    }
    return 0;
}

//递推求解
void Bell(int n, int mod)
{
    bell[1][1] = 1;
    for(int i = 2; i <= n; i ++){
        bell[i][1] = bell[i - 1][i - 1] % mod;
        for(int j = 2; j <= i; j ++)
        bell[i][j] = (bell[i][j - 1] + bell[i - 1][j - 1]) % mod;
    }
}


 

斐波那契数列

任意一个数是其前两位数只和,即f(i)=f(i-1)+f(i-2),f(1)=f(2)=1

该数列也满足黄金分割比例,所以又成为黄金分割数列

#include<stdio.h>
int main()
{
    __int64 s[51]={0,1};
    int i;
    for(i=2;i<=50;i++)
        s[i]=s[i-2]+s[i-1];
    int n;
    while(scanf("%d",&n)&&(n!=-1))
        printf("%I64d\n",s[n]);
    return 0;
    
}


 

卡特兰数

 

实际上就是出栈序列的种数

令h(0)=1,h(1)=1,catalan数满足递推式:

h(n)= h(0)*h(n-1)+h(1)*h(n-2) + ... + h(n-1)h(0) (n>=2)

例如:h(2)=h(0)*h(1)+h(1)*h(0)=1*1+1*1=2

h(3)=h(0)*h(2)+h(1)*h(1)+h(2)*h(0)=1*2+1*1+2*1=5

另类递推式:

h(n)=h(n-1)*(4*n-2)/(n+1);

递推关系的解为:

h(n)=C(2n,n)/(n+1) (n=0,1,2,...)

递推关系的另类解为:

h(n)=c(2n,n)-c(2n,n-1)(n=0,1,2,...)

#include<stdio.h>
int main()
{
   __int64 a[36];
   int i,j;
   a[1]=1;
   for(i=2;i<=35;i++)
   a[i]=a[i-1]*1.0/(i+1)*(4*i-2);
   int n;
   int x=1;
   while(scanf("%d",&n))
   {
       if(n==-1)
       break;
   printf("%d %d %I64d\n",x,n,2*a[n]);
   x++;
   }
   return 0;
}

组合数学公式

一.特殊的排列组合:

1.在n个不同物体中,可重复地选取r个物体的排列数为: n^r;

2.在n个不同物体中,可重复地选取r个物体的组合数为C(n+r-1, r);

3.在从A={1,2,…n}中取r个不相邻的数进行组合,其组合数为C(n-r+1,r);

4.n个物体中不相同的物体的总数是k个,即n=n1+n2+ ··· +nk,则这几个物体全排列数是: n! / (n1! * n2! * ··· * nk!);

5. 圆周排列(选取的物体不分先后):A(n, r) / r;

6. 项链排列(在圆周排列的基础上,正面向上和反面向上两种方式放置各个数是同一个排列) :A(n, r) / 2r;

二.组合恒等式:

1. C(n, r) = C(n, n-r);

2. C(n,k) = C(n-1, k) + C(n-1, k-1);

3. C(n+r+1, r) = C(n+r, r) + C(n+r-1, r-1) + C(n+r-2, r-2) + ··· + C(n+1, 1) + C(n, 0);

4. C(n, k)C(k, r) = C(n, r)C(n-r, k-r);

5. C(m+n, r) = C(m, 0)C(n, r) + C(m,1)C(n, r-1)+ ··· + C(m, r)C(n, 0);

位运算

去掉最后一位 101101->10110x >> 1

在最后加一个0 101101->1011010x << 1

在最后加一个1 101101->1011011(x << 1)+1

把最后一位变成1 101100->101101x | 1

把最后一位变成0 101101->101100(x | 1)-1

最后一位取反 101101->101100x ^ 1

把右数第k位变成1 101001->101101, k=3x | (1 >> (k-1))

把右数第k位变成0 101101->101001, k=3x & ! (1 << (k-1))

右数第k位取反 101001->101101, k=3x ^ (1 << (k-1))

取末三位 1101101->101x & 7

取末k位 1101101->1101, k=5x & (1 << (k-1))

取右数第k位 1101101->1, k=4x >> (k-1) && 1

把末k位变成1* 101001->101111, k=4x | (1 << (k-1))

末k位取反 101001->100110, k=4x ^ (1 << (k-1))

把右边连续的1变成0 100101111->100100000x & (x+1)

把右起第一个0变成1 100101111->100111111x | (x+1)

把右边连续的0变成1 11011000->11011111x | (x-1)

取右边连续的1   100101111->1111   (x ^ (x+1)) >> 1

去掉右起第一个1的左边   100101000->1000 x & (x ^ (x-1))

对于a[n] 求数列中任意两个不同的数(有序)之积的和

(a1+a2+a3+……+an)^2-a1^2-a2^2-……-an^2=

2*a1*a2+2*a1*a3+……2*an-1*an

(解决联合权值子问题二)

 

乘法逆元(线性)

令t=mod/i,k=mod%i
则(t*i+k)%mod=mod%mod=0%mod
-t*i%mod=k%mod
-t/k %mod=1/i %mod
-t*inv[k]%mod=in[i]%mod
inv[i]=(-mod/i)*inv[mod%i]%mod
inv[i]=(mod-mod/i)*inv[mod%i]%mod

扩欧理解

特别地,一定存在整数x,y,使ax+by=d成立。
它的一个重要推论是:a,b互质的充要条件是存在整数x,y使ax+by=1.

假设 a>b,
(1)  b=0  gcd(a,b) = a ,  ax = a ,  则x=1,y=0;(这里推荐不把gcd(a,0)理解成最大公约数,而是一个计算机求出来的值)
(2) 假设 ax1+by1=gcd(a,b) (方程一) bx2+(a%b)y2=gcd(b,a%b)(方程二);由欧几里得算法gcd(a,b) =gcd(b,a%b) 得到,
ax1+by1 = bx2+(a%b)y2,即ax1+by1=bx2+(a-a/b*b)y2 ax1+by1=ay2+b(x2-a/b*y2)
在根据多项式恒等定理(把a,b看成变量),x1=y2; y1=x2-a/b*y2;

组合数

C(n,m)=(n!)/((n-m)!*m!)

可以通过求(n-m)!*m!在%MOD意义下的逆元 求解组合数

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!