忽略电路板厚度,假定温区内部恒温
通过热传导方程得到不同温区之间的空隙中,温度在空间上线性分布
通过牛顿冷却定律和比热容公式解微分方程可知,物体在恒温环境下温度随时间的函数
然后由附件数据分段拟合参数
下面是拟合的代码
1 | import numpy as np |
第一问代码:
1 | import numpy as np |
得到的各点温度:
1 | [135.71310782] |
炉温曲线:
大力枚举速度v,先大范围粗糙枚举,再小范围精确枚举
需要复用许多第一问的代码,所以函数化编程很重要,同时也要封装好来
1 | import numpy as np |
得到的各参数:
1 | v1=72.0 |
在最大速度下的炉温曲线:
把阴影面积作为估值函数,做模拟退火
调了scikit-opt
的库
然后还画了最小面积随迭代次数变化的曲线
1 | from sko.SA import SA, SABoltzmann, SAFast |
1 | best_x=[1.06929985e+01 1.97873914e+01 5.68152357e+00 8.90629441e-03 1.99983037e+01] |
把炉温曲线中相同温度的点的时间做平均值,与峰值时间的平方和作为对称性的衡量标准
然后本问是多目标优化,即阴影面积和对称度
这里采用的是线性组合作为估值函数,经过多次尝试,发现面积变化始终不大,而对称性比较敏感,最终选择了1:10的比例赋权
1 | from sko.SA import SA |
1 | best_x=[12.12066253 2.29087199 0.94809455 19.92827282 19.99803738] |
scipy.integrate.odeint()
可以数值解一阶微分方程(组)
不同于微分方程的符号解,可以给出未知函数的表达式,数值解只能求得指定位置的函数值
sol=odeint(func, y0, t)
func
:表示一个微分方程\(\frac{\text dy}{\text dt} = func(y, t)\),其中的y
可以是向量,以表示微分方程组y0
:未知函数的初值条件,表示\(y(t[0])=y_0\),即第一个自变量取值处的函数值,同样可以是向量t
:自变量的取值序列返回值sol
是一个len(t)*len(y0)
的数组,表示每个取值位置的函数值
示例: \[\begin{cases}y'=-2y+x^2+2x \\y(1)=2\end{cases}\] 代码在下面一起给出
通过换元可以将高阶微分方程转化为一阶微分方程: \[y_0=y \\y_1=y_0'=y' \\y_2=y_1'=y'' \\\dots \\y_k=y_{k-1}'=y^{(k)} \\\] 这样就同样可以使用odeint()
来获得数值解了
示例: \[\begin{cases}y''+2y'+2y=0 \\y(0)=0, y'(0)=1\end{cases}\] 先转化成: \[\begin{cases}y_0'=y_1 \\y_1'=-2y_1-2y_0 \\y_0(0)=0, y_1(0)=1\end{cases}\]
1 | import numpy as np |
输出:
1 | [[ 2. 2.08484933 2.9191691 4.18723381 5.77289452 7.63342241 |
Lorenz模型的混沌效应
Lorenz方程: \[\begin{cases}\dot x=\sigma(y-x) \\\dot y=\rho x-y-xz \\\dot z=xy-\beta z\end{cases}\] 模拟\(\sigma=10,\rho=28,\beta=\frac 8 3\)时\(t\in [0,50]\)的运行轨迹,以及给初值微小扰动后解的偏差演化曲线
1 | import numpy as np |
scipy.misc.derivative
可用于求任意函数的任意阶导数:
def derivative(func, x0, dx=1.0, n=1, order=3)
func
:自定义的被求导函数\(f(x)\)x0
:求导的位置,即求\(f^{(n)}(x_0)\)dx
:用于微分的小量n
:求导的阶数order
:用于求导的采样点个数,必须为>=n+1的奇数示例:
画出\(\cos\sqrt{x^2+1}\)及其在\(0\)点处的\(1,3,5\)阶泰勒展开式 \[f(x)=f(x_0)+f'(x_0)(x-x_0)+\frac{f''(x_0)}{2!}(x-x_0)^2+\dots+\frac{f^{(i)}(x_0)}{i!}(x-x_0)^i+\dots\]
1 | import numpy as np |
scipy.integrate.quad
可以求任意函数的一重积分
quad(func, a, b)
表示求函数func
从a
到b
的一重积分
示例:
求\(\int_0^\infty e^{-x}\sin(x^2+2)\)
1 | import numpy as np |
输出:
1 | (0.37378979243874044, 1.3876530327162045e-08) |
返回的值分别是积分结果和绝对误差
scipy.integrate.dblquad
和scipy.integrate.tplquad
分别能够求二重和三重积分
dblquad(func,a,b,gfun,hfun)
表示\(\int_a^b \text dx \int_{gfun(x)}^{hfun(x)} func(x,y) \text dy\)
tplquad(func,a,b,gfun,hfun,qfun,rfun)
表示\(\int_a^b \text dx \int_{gfun(x)}^{hfun(x)} \text dy \int_{qfun(x,y)}^{rfun(x,y)} func(x,y,z) \text dz\)
返回值和quad
一致
需要注意的是,func
定义的参数顺序必须是func(x,y,z)
scipy.optimize.fsolve
可以解非线性方程(组)
fsolve(func,x0)
表示求\(func(x)=0\)的根,迭代初值x0
若要解方程组,可将func(x)
的x
定义为向量
示例: \[x^3+1.1x^2+0.9x-1.4=0 \\\begin{cases}5x_2+3=0 \\4x_1^2-2\sin(x_2x_3)=0 \\x_2x_3-1.5=0\end{cases}\]
1 | import numpy as np |
输出:
1 | [0.67065731] |
scipy.optimize.minimize
是求非线性规划的函数,若不加约束,即可求任意函数(一元,多元)的极小值点
minimize(func,x0)
表示求\(func(x)=0\)的最小值,迭代初值x0
返回的是一个result
类,可以调用成员以获取相应信息
示例: \[f_1(x)=e^x\cos(2x) \\f_2(x_1,x_2)=100(x_2-x_1^2)^2+(1-x_1)^2\]
1 | import numpy as np |
输出:
1 | fun: -0.2344426467071059 |
1 | import numpy.linalg as la |
输出:
1 | 3.7416573867739413 |
scipy.linalg.null_space()
可以获得基础解系 \[\begin{cases}x_1 -5x_2 +2x_3 -3x_4=0 \\5x_1 +3x_2 +6x_3 -x_4=0 \\2_1 +4x_2 +2x_3 +x_4=0 \\\end{cases}\] 的基础解系:
1 | import numpy as np |
输出:
1 | [[ 0.79428706 -0.07832183] |
两个列向量即为基础解系
numpy.linalg.pinv()
可以求矩阵的伪逆矩阵,这样对于形如\(Ax=b\)的线性方程组,pinv(A)@b
就可以得到一组解
一般地,当方程组有:
numpy.linalg.eig()
可以得到矩阵的特征值和特征向量
返回二元组分别是特征值和特征向量的list,特征向量表示为列向量
例如: $$ A=,
P=,
=$$ 验证\(P^{-1}AP=\Lambda\)
1 | import numpy as np |
输出:
1 | [ 1. -8. 1.] |
往往需要提前指定\(f(x)\)的类型,常用的有某次多项式、双曲函数、指数函数等
scipy.optimize.curve_fit
可以实现任意类型函数的拟合
用法:
curve_fit(f, xdata, ydata, p0=None)
f
为一函数:f(x,...)
,x
为自变量,后面的参数全为拟合函数的待定参数xdata
和ydata
是数据点的坐标向量p0
为待定参数的初值向量xdata
是D维向量构成的序列,p0同返回二元组(popt,pcov)
:
popt
:一维数组,表示拟合函数的参数pcov
:二维阵列,popt
的估计协方差。对角线提供参数估计的方差。示例:
用二次多项式拟合一元函数
1 | import numpy as np |
输出:
1 | a=-9.810839009366013, b=20.129292913034863, c=-0.03167107877459929 |
对曲面\(z=e^{-\frac{(x-\mu_1)^2+(y-\mu_2)^2}{2\sigma^2}}\)添加噪声,再进行拟合,其中\(\mu_1=1,\mu_2=2,\sigma=3\)
1 | import numpy as np |
输出:
1 | u1=1.0055785483402968, u2=2.002582704331591, sgm=3.0134682873777496 |
在数据分析中很有用
拉格朗日插值的\(f(x)\)为\(n-1\)次多项式,\(n\)为数据点个数
可以证明,任意\(n\)个数据点的\(n-1\)次插值函数存在且唯一
具体来说, \[f(x)=\sum_{i=0}^n l_i(x)y_i \\l_i(x)=\prod_{j=0,j\neq i}^n \frac {x-x_j} {x_i-x_j}\] 由此公式容易用Python实现拉格朗日插值
但是一次性将所有数据点进行插值,次数过高,不仅复杂度高,误差也大,因此常进行分段插值,即用分段函数表示\(f(x)\)
单纯的分段插值得到的函数性质往往不够好(光滑性)
对于划分:\(\Delta:a=x_0<x_1<\dots<x_n=b\),\(m\)阶样条插值函数需要满足:
显然阶梯插值为0阶样条插值,折线插值为1阶样条插值
一般直接使用scipy.interpolate
实现的样条插值
scipy.interpolate
求解插值问题interp1d
)interp1d(x,y,kind='linear')
前两个参数为数据点向量,kind指定插值方法:
kind | 说明 |
---|---|
'next','previous' | 阶梯插值,值为最近的前/后一个\(y_i\) |
'zero', 'linear', 'quadratic', 'cubic' | 0,1,2,3阶样条插值 |
0,1,2,3,5,... | 用int 指定样条插值的阶数,3以上只能为奇数 |
返回一个插值函数,可以传入\(x\)返回\(f(x)\),也可以传入\(\vec x\)返回\(f(\vec x)\)
示例:
1 | import numpy as np |
interp2d
)interp2d(x,y,z,kind='linear')
接受网格分布的数据点进行插值
x,y为坐标向量,z为数据矩阵
返回一个插值函数,输入x,y向量即可获得数据矩阵
1 | from IPython.core.pylabtools import figsize |
griddata
)若数据点并无分布规律,可用griddata
进行插值
可处理任意D维的数据点
griddata(points, values, xi, method='linear')
points
为数据点位置(D维向量)的序列,values
为数据点值的序列
xi
为需要插值的空间,形式与points
相同,或用格点坐标矩阵的D元组表示
method
插值方法:'nearest','linear','cubic'
分别对应0,1,3阶插值
返回xi
中的数据值
1 | from mpl_toolkits import mplot3d |
因此最优解也不一定在可行域边界上,一般而言用迭代算法得到的也只是局部最优解
标准模型如下: \[\min f(\vec x) \\\text{s.t.}\begin{cases} g_i(\vec x) \geq 0,\ \ \ i=1,2,...,m, \\ h_i(\vec x) = 0,\ \ \ i=1,2,...,l,\end{cases}\] scipy.optimize.minimize
可以解决非线性规划问题
用法:
minimize(fun,x0,bounds=None,constraints=None)
其中fun
为目标函数,输入一个向量\(\vec x\)返回对应值
x0
为迭代初值,决定是否能取到全局最优解
bounds
与线性规划的linprog
一样
constraints
为约束条件,具体实现为单个dict或dict的序列,每个dict应有两个键值:
type
:字符串'eq'
和'ineq'
之一,表示该约束为等号约束或不等号约束
fun
:函数,传入向量\(\vec x\),返回约束式的左值,在可行解中该值大于等于0(不等号约束)/等于0(等号约束)
特别地,若有一系列约束为线性约束,则可将一系列右值视为一个向量,利用numpy.array
重载的比较符号,
将这些约束缩为一个,即lambda x:b-A@x
scipy.optimize.linprog
可以解决线性规划问题标准模型: \[\min_x \ z= c^T x, \\ \mbox{s.t.} \ \begin{cases} A x \leq b,\\ A_{eq} x = b_{eq},\\ l \leq x \leq u . \end{cases}\] 其中\(A\)和\(A_{eq}\)分别是不等约束和等号约束的系数矩阵,\(l\)和\(u\)是上下界向量
用法:
linprog(c, A=None, b=None, Aeq=None, beq=None, bounds=None)
前5个参数对应标准模型,bounds是一个由(li,ui)
组成的序列,表示每个xi
的边界
当bounds
为None
时,默认下界全为0,上界全为正无穷
返回的对象记为res
,具有以下属性:
res.fun
为目标函数的最小值,res.x
为最优解
示例: \[\min_x \ z= -x_1+4x_2, \\ \mbox{s.t.} \ \begin{cases} -3x_1+x_2 \leq 6,\\ x_1+2x_2 \leq 4,\\ x_2 \geq -3 . \end{cases}\]
两种方式求解:
1 | from scipy.optimize import linprog |
输出:
1 | -21.99999984082492 |
x=symbols('x')
声明变量\(x\)
y.subs(x,x0)
\(y\)是\(x\)的表达式时,带入\(x=x_0\)的值
y.n()
常量表达式求浮点值
limit(e, z, z0, dir="+")
\(e\)是\(z\)的表达式,求\(e(z)\)在\(z_0\)处的极限,\(\text{dir}\)可以指定是\(z_0^+\)还是\(z_0^-\)
以下计算了\(\lim_{x\rightarrow 0}\frac{\sin x}x\),\(\lim_{x\rightarrow \infty} (1+\frac 1 x)^x\),\(\lim_{x\rightarrow 0}\sin(\frac 1 x)\)三个极限
1 | from sympy import * |
输出:
1 | 1 |
diff(expr,x1,n1,x2,n2,...)
表达式expr
依次对xi
求ni
阶偏导,ni
不写默认为1
\(z=\sin x+x^2e^y\),求\(\frac{\partial^2 z}{\partial x^2},\frac{\partial z}{\partial y},\frac{\partial^2 z}{\partial x\partial y}\)
1 | from sympy import * |
输出:
1 | 2*exp(y) - sin(x) |
summation(expr,(i,a,b))
expr是关于i的函数,求\(\sum_{i=a}^b expr(i)\)
示例:\(\sum_{k=1}^n k^2\)和\(\sum_{k=1}^\infty \frac 1 {k^2}\)
1 | from sympy import * |
输出:
1 | n*(n + 1)*(2*n + 1)/6 |
series(expr, x=None, x0=0, n=6, dir="+")
\(expr\)是\(x\)的表达式,在\(x_0\)处的\(n\)阶展开,\(\text{dir}\)可以指定是\(x_0^+\)还是\(x_0^-\)
下面演示了\(\sin x\)在0点的3,5,7阶泰勒展开式
1 | from pylab import rc |
输出:
1 | x + O(x**3) |
不定积分:
integrate(f,x)
相当于\(\int f(x)\mathrm d x\)
定积分:
integrate(f,(x,a,b))
相当于\(\int_a^b f(x)\mathrm d x\)
以下代码求解\(\int_0^\pi \sin(2x)\mathrm d x,\int_0^{+\infty} \frac {\sin(x)} x\mathrm d x,\int \sin(x)e^x\mathrm d x\)
1 | from sympy import * |
输出:
1 | 0 |
solve(expr,x)
求解方程\(expr=0\),其中\(x\)是自变量
返回一个list存放所有的根
solve([...,expr_i,...],[...,x_i,...])
求解方程组,其中\(expr_i\)对应\(x_i\)
返回一个list存放所有根,每个根用一个tuple表示,对应此根所有各个变量的值
roots(expr,x)
返回一个dict,表示每个根以及它的重数
示例: \[x^3-1=0 \\(x-2)^2(x-1)^3=0 \\\begin{equation} \begin{cases} x^2+y^2=1 \\ x-y=0 \end{cases}\end{equation}\]
1 | from sympy import * |
输出:
1 | [1, -1/2 - sqrt(3)*I/2, -1/2 + sqrt(3)*I/2] |
微分方程中的\(y\)是关于\(x\)的函数,而且是未知函数,而非未知量,因此要将\(y\)声明为Function
y=Function('y')
y=symbols('y',cls=Function)
两种写法都是可以的
dsolve(eq,f(x),ics=)
,其中eq
是关于f(x)
的表达式,求解\(eq=0\)
ics可以以一个dict指定f(x)的初值
示例: \[y''-5y'+6y=0 \\y''-5y'+6y=xe^{2x} \\y''-5y'+6y=0,y(0)=1,y'(0)=0 \\y''-5y'+6y=xe^{2x},y(0)=1,y(2)=0\]
1 | from sympy import * |
输出:
1 | Eq(y(x), (C1 + C2*exp(x))*exp(2*x)) |
单个图像:
plot(expr, range, **kwargs)
其中expr
为表达式,表达式由sympy.abc
导入的符号组成
range
为三元组(x,l,r)
,指定了自变量以及上下界
**kwargs
指定的参数与matplotlib
类似,这里不做过多介绍
多个图像在同一范围:
plot(expr1, expr2, ..., range, **kwargs)
多个图像在不同范围:
plot((expr1, range1), (expr2, range2), ..., **kwargs)
以下代码画出了\(y_1=2\sin x,\ x\in [-6,6]\)和\(y_2=\cos(x+\frac \pi 4),\ x\in [-5,5]\)的图像
1 | from sympy.plotting import plot |
\(z=\sin(\sqrt{x^2+y^2})\)
1 | from pylab import rc |
用sumpy.Eq
表示一个方程
Eq(expr_a,expr_b)
表示等式两边分别是expr_a,expr_b
Eq(expr)
等价于Eq(expr,0)
\((x-1)^2+(y-2)^2-4=0\)
1 | from pylab import rc |
Matplotlib.pyplot
将原本面向对象的作图操作封装成函数,使之更近似于MATLAB的交互式命令只要有离散的数据,就可以做出柱状、散点、饼状、折线、3D图形等可视化图表
pyplot.bar()
只需提供两个数组作为各数据的横纵坐标,即可生成柱状图
1 | from matplotlib import rcParams |
效果图:
若要显示负号,需rcParams['axes.unicode_minus']=False
与bar
类似
1 | from numpy.linalg.linalg import _eigvalsh_dispatcher |
基本用法为plot(x,y,s)
,前两个参数为数据点的横纵坐标,s为指定线条颜色、线条样式和数据点形状的字符串
也可在同一个坐标内显示多个折线
1 | import numpy as np |
只需一维数组
1 | from matplotlib import rcParams |
subplot(nrows, ncols, index)
前两个参数将整个窗口分为nrows*ncols
的区域
函数返回从上到下,从左到右的第index
个区域(从1开始)
1 | import numpy as np |
上方的两个窗口分别占据了2*2划分的前两个区域
下方窗口占据了2*1划分的第二个区域
以下代码画出\(x=t\sin t,y=t\cos t,z=t\)的图形
1 | from matplotlib.pyplot import * |
plot_surface
生成表面图形,plot_wireframe
生成网格图形
生成三维曲面时,需指定网格坐标(描点坐标)
以下代码画出\(z=\sin (\sqrt{x^2+y^2})\)的图形
1 | from matplotlib.pyplot import * |
1 | from matplotlib.pyplot import * |
以下代码画出向量场\(\vec A=(y\cos x,y\sin x)\)
quiver(x, y, vx, vy)
分别接收两个网格坐标矩阵,以及向量场的xy分量
1 | from matplotlib.pyplot import * |
我们项目中只涉及轻量级的数据库操作,因此使用LitePal中封装好的接口可以大大简化操作
建议全程使用LitePal进行开发
注意:以下有些步骤是我已经完成的,请务必先将本地工程更新至仓库中的最新版本
在app/build.gradle
中添加对LitePal的引用:
1 | dependencies { |
注意使用最新版本3.2.3
在assets
中创建litepal.xml
:
1 | <?xml version="1.0" encoding="utf-8"?> |
其中dbname
指定数据库名,version
指定数据库版本(增减数据表、增减数据表字段、改变字段类型等操作都必须增加版本号)
在list
中使用mapping
标签关联每个数据表
在AndroidManifest.xml
配置:
1 | <manifest> |
LitePal将数据表和java类一一对应,因此对对象的操作就很容易转化成对数据表的操作
在com.hitsz.eazytime.model
包下新增一个java文件用于定义类:
1 | public class Todo extends LitePalSupport { |
LitePal支持的数据类型一共有8种:int、short、long、float、double、boolean、String、Date
id
字段:无论类中定义与否,数据表里都会存在,且作为自增主键使用,但在类中定义id
及getId
可以方便查询
代码规范:类中的所有成员必须以private定义,取值和修改必须经过get和set函数
注意:新版本LitePal的数据表类应当继承自LitePalSupport
而非DataSupport
注意:修改了类的定义后,请务必增加数据库的版本号,否则对类的更改无法应用至数据库
这部分在《第一行代码》和作者博客里有较详细的介绍,这里有重点地讲一下
一般new一个新的对象出来,然后save就可以了
1 | Todo todo=new Todo(...); |
注意:新版的查询使用LitePal
而非DataSupport
1 | List<Todo> todos = LitePal.select(...).where(...).order(...).limit(...).offset(...).find(Todo.class) |
以上连缀无固定顺序,也可不写其中的某些连缀
注:LitePal本身支持关联表的激进查询,但不推荐使用,合理的写法是在类中实现一个返回关联字段的函数,详细请看作者博客
没什么要说的,见作者博客
没什么要说的,见作者博客
]]>这是写给大一立项小组成员看的简易版git教程
我们做这个项目只需要一些基本的git命令就可以了,因此这里教大家10min速成git
git是版本管理工具,适合多人合作,储存代码的地方叫做仓库,仓库可以在本地,也可以在学校的服务器上,GitHub是个托管仓库的网站,大家经常把代码放在GitHub上
在这里下载并安装git,看不懂就一直点next就行
git是一个命令行工具,要使用它只能敲对应的命令
下面介绍的命令均在对应目录下的命令行中执行
clone是将网络上的仓库克隆到本地的操作
1 | git clone "https://github.com/linkfqy/EazyTime.git" |
上面的命令将我们项目的工程文件clone至当前目录
当前目录会生成一个EazyTime文件夹即工程文件夹,打开它并重新打开命令行,后续命令均在此文件夹中进行
clone到本地后,你就可以对工程文件进行编辑了,可以任意增加想要的功能
一般来说,我们只希望自己工作的那部分文件能够更新到仓库,而无关紧要的修改不应影响他人
因此需要对工作文件进行add
add命令将指定的文件或目录添加至本地的暂存区,只有add过的文件才能被提交,add过的文件还可以修改,也可以再次add,最终提交的文件以最后一次add的版本为准
如:
1 | git add "README.md" |
以上命令将README.md
文件添加至本地的暂存区
1 | git add "app\src\main\java" |
以上命令将app\src\main\java
整个文件夹添加至本地的暂存区
1 | git add * |
以上命令将所有文件添加至本地的暂存区
注意:不要随意使用以上命令!因为这会将你对工程做的所有修改(而非仅属于你的那部分工作)都添加!一旦push,会对所有人共用的仓库产生影响!
合适的做法是,仅add自己工作所属的目录,如:
1 | git add "app\src\main\java\com\hitsz\eazytime\ui\todo" |
git status
命令用于显示工作目录和暂存区的状态。
使用此命令能看到哪些修改被暂存到了, 哪些没有,哪些文件还没被add。git status
不显示已经commit
到项目历史中去的信息。
“Changes to be committed”所列的是已add过的文件版本 “Changed but not updated”所列的是add过但被修改,尚未再次add的文件 “Untracked files”中所列的是尚未add的文件
1 | Changes to be committed: |
以上表示README.md
被add过一个版本,但之后又修改过,可以再次add以添加新的版本
同时也提示你:
git restore --staged "README.md"
命令README.md
的修改,使用git restore "README.md"
将文件变为最后一次add的版本commit
命令将暂存区的内容添加到本地仓库中
1 | git commit -m "message" |
上面的message是对此次提交的注释,可以写点关于这次提交干了啥的解释
终于到了最后一步,将本地所作的修改提交至GitHub上的仓库
注意:之前的操作都是本地的,不push大家是看不到你的工作的
1 | git push |
一句话将本地仓库提交至GitHub
如果想要提交对应分支,则:
1 | git push origin main |
将本地的main分支提交至GitHub
第一次push可能会弹出登录窗口,登录github账号就可以正常提交了
]]>今天遇到了这样一个问题:
1 | class ListNode: |
可见,a.set()
并没有改变a的值,不得其解
看了这篇文章
豁然开朗,之前理解有误的原因是自动把C++的赋值与Python混淆了
Python的变量,其实是C++意义上的指针
下面摘录几段:
Python 的构造函数将构造匿名对象,且返回此对象的一个指针。
这是 Python 与指针的第一个重要联系。
用代码描述,对于Python代码:
1 | sampleNum = 0 |
其不类似于 C++ 代码:
1 | int sampleNum = 0; |
而更类似于:
1 | int __tmpNum = 0, *sampleNum = &__tmpNum; |
Python 与指针的另一个重要联系在于 Python 的隐式解指针行为。
虽然 Python 不存在显式解指针操作,但(有且仅有)__setitems__操作将进行隐式解指针,通过此方法对变量进行修改等同于通过解指针操作修改变量原值。
此种性质意味着:
对于Python代码:
1 | numList = [None] * 10 |
其相当于:
1 | int *numList = new int[10]; |
由此可见,对 numList 的非__setitems__操作,导致 numList 被绑定到了一个新指针上。
由于 Python 对哈希表的高度依赖,“涉及__setitems__的操作”在 Python 中实际上是一个非常广泛的行为,这主要包括:
于是,将set()
改为这样:
1 | def set(self, L): |
就解决了问题
self
是默认将实例本身传入的参数,根据上文,实际传入的是实例的指针,而self=ListNode(val=L[0])
将self
重新绑定至一个新建的节点,那么后续进行的操作就与原实例无关了
很明显是最大权闭合子图的模型
示例程序:
1 |
|
直接莫队……用bitset维护出现过哪些值 \[a-b=x\Leftrightarrow a=b+x \\a+b=x\Leftrightarrow a=-(b-x)\]
对于操作1,bitset左移x位后对自己取并
对于操作2,需要同时维护一个所有值的相反数的bitset,同1
对于操作3,直接爆枚因子即可
时间复杂度\(O(n\sqrt n)\)
示例程序:
1 |
|
显然可以把整个图黑白染色,得到一个二分图
考虑二分图最大匹配,如果初始点是未匹配点,则Bob只能走未匹配边到一个匹配点,而Alice一定可以沿匹配边走回左边的匹配点,由于不能往回走,此时的情形与初始状态一样,最终Bob输
如果初始点是匹配点,此时Bob走的是匹配边,Alice走未匹配边,如果最后能走回左边则Alice赢,否则Bob赢。其实他们走的是增广路,Alice能赢当且仅当初始点不一定是匹配点
所以答案是所有【不一定是匹配点】的点
具体做法是从左边未匹配点出发,沿增广路遍历到的所有左边点都是答案
示例程序:
1 |
|
直接乱搞即可
示例程序:
1 |
|
考虑一个区间除后变化量如果都相同,就转化为区间减了
维护最大值和最小值即可判断
复杂度证明:
考虑两个数\(a,b\),差是\(a-b\),除以\(d\)后差是\(\frac{a-b}d\)
也就是说两个数被除\(\log\)次就相等了
令一个线段树节点的势能为\(\log(Max-Min)\)
操作2就相当于把区间内所有势能不为1的节点势能-1,代价为势能减小总量
操作1会将\(\log\)个节点的势能恢复为\(\log(Max-Min)\)
总时间复杂度为整个过程中产生的势能总量\(O((n+q\log n)\log a_i)\)
示例程序:
1 |
|