状态数组
状态表示数组DP[N][N],一般是二维,表示从i到j对应的答案数
对于区间合并问题.状态转移方程一般是,将一个大区间分成两个小区间,这两个小区间的状态已经计算出,思考这两个小区间计算出大区间的状态;
插入知识点:二叉树的三种遍历
先序遍历:根左右
中序遍历:左根右
后序遍历:左右根
中午没睡觉,下午脑子昏昏沉沉的,看不懂区间dp了,所以选择把算法提高课的基础算法重新看一遍
下面这个问题有关数据溢出的知识
## 64位整数乘法
输出一个整数,表示a*b mod p的值。
数据范围
1≤a,b,p≤1018
ll a,b,p;
cin>>a>>b>>p;
ll ans = 0;
while(b)
{
if(b&1)
{
ans = (ans+a)%p;
}
a = (a<<1)%p;//这里最好用a<<1,而不是写a*2,因为a*2可能会超出数据范围,而a<<1永远不会超出数据范围
//如果当前位是64位,那他不会变成65位,因为多的那一位会被挤掉(因为被挤掉的那一位表示的数值肯定是大于p的,取模之后也肯定是会被去掉,所以不影响答案),然后经过取模,得到正确的答案
b>>=1;
}
RMQ算法(快速求区间最大值)
for (int i = 0; i <= 18; i++)
{
for (int j = 1; j + (1 << i) - 1 <= n; j++)
{
if (!i)
{
f[j][i] = a[j];
}
else
{
f[j][i] = max(f[j][i - 1], f[j + (1 << (i - 1))][i - 1]);
}
}
}
#排序
问题一 环形均分纸牌问题:
一共有n个人围成一圈,每个人a[i]张纸牌,如果最终每个人纸牌数量相同,那么需要互相传递的纸牌总数是多少.
for (int i = 1; i <= n; i++)
{
a[i] += a[i - 1];//前缀和,前i个人一共有多少张纸牌
}
if (a[n] % n)
{
return -1;//如果不能均分,则直接退出
}
c[1] = 0;
int avg = a[n] / n;//最终每个人多少张牌
for (int i = 2; i <= n; i++)
{
c[i] = a[i - 1] - (i - 1) * avg;///重点/,c[i]表示如果让前i-1个人满足要求,那么第i个人需要给他们多少张,或者他们给第i个人多少张
}
sort(c+1,c+1+n);//排序之后,找中位数
ll sum = 0;
for (int i = 1; i <= n; i++)
{
sum += abs(c[i] - c[(n+1)/2]);//对数组c进行操作,记住就行,
}
return sum;
一个大根堆一个小跟堆实现快速查找中位数
if(p.empty()||a<=p.top())
p.push(a);
else q.push(a);
if(p.size()>q.size()+1)
{
int k = p.top();
p.pop();
q.push(k);
}
if(q.size()+1>p.size())
{
int k = q.top();
q.pop();
p.push(k);
}