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意义下的逆元 求解组合数
来源:CSDN
作者:Nice try
链接:https://blog.csdn.net/zRNA__/article/details/79354731