收藏 分销(赏)

动态规划--斜率优化.doc

上传人:s4****5z 文档编号:9434967 上传时间:2025-03-26 格式:DOC 页数:14 大小:80.50KB 下载积分:10 金币
下载 相关 举报
动态规划--斜率优化.doc_第1页
第1页 / 共14页
动态规划--斜率优化.doc_第2页
第2页 / 共14页


点击查看更多>>
资源描述
动态规划优化_斜率优化 先来看一道题(HDU3507): 题意:给出N个单词,每个单词有个非负权值Ci,将k个单词排在一行的费用为(∑Ci)^2+M.求最优方案,使得总费用最小. 我们很容易得到一个O(N^2)的算法: s[i]表示前i个单词的权值和. 先写个东西在这:所有元素非负的数组的前缀和值随下标增加单调递增.后面会用到. f[i]表示将前i个单词排版完毕后的最优值,f[i]=min{f[j]+(s[i]-s[j])^2+M}. 但题目中N的范围是500000.这个算法明显不行.考虑如何优化. 我们固定i,考虑它的两个一般决策点j,k(j<k). 记g[pos]=f[pos]+(s[i]-s[pos])^2+M,即i从pos转移的代价. 如果决策点k优于j,那么就有g[k]<g[j].展开来: f[k]+(s[i]-s[k])^2+M<f[j]+(s[i]-s[j])^2+M,化简得 f[k]-f[j]+s[k]^2-s[j]^2<2*s[i]*(s[k]-s[j]) 注意到s[k]>s[j],我们在不等式两边除以(s[k]-s[j]). 不等式化为(f[k]-f[j]+s[k]^2-s[j]^2)/(s[k]-s[j])<2*s[i]. 方便起见,我们将左边分式的分子分母同时变号. (f[j]-f[k]+s[j]^2-s[k]^2)/(s[j]-s[k])<2*s[i]. 可以看到不等式左边与i无关,右边只与i有关.(而且左边像一个两点间的斜率式). 记slope[j,k]=(f[j]-f[k]+s[j]^2-s[k]^2)/(s[j]-s[k]). 好了,现在我们有一个结论. △对于i的两个决策点j,k(j<k),决策k优于决策j就等价于slope[j,k]<2*s[i]. 换句话说,如果slope[j,k]<2*s[i],那么决策k优于j,反之决策j不比k差. 其实我们还可以知道,决策点k永远会比决策点j优.因为对于以后的i',s[i']>s[i]>slope[j,k]. 因此这里的优劣应该是全局的,而不只限于i. 我们再来考虑三个点j,k,l(j<k<l)之间的优劣关系. 还是通过斜率: 如果slope[j,k]>slope[k,l],我们看看能得到什么. 1.若slope[k,l]<2*s[i].那么由之前的结论(△),l比k优. 2.若slope[k,l]>2*s[i],则slope[j,k]>2*s[i],那么由之前的结论(△),决策j不比k差. 综上,如果slope[j,k]>slope[k,l],k是可以淘汰掉的. 我们又得到一个结论. △对于三个决策点j,k,l(j<k<l),如果slope[j,k]>slope[k,l],那么k永远不会成为某个点的最优决策. 现在我们有了这两个结论,怎样来优化呢? 我们可以将决策放到一个队列中,利用以上两个结论剔除无用决策点,达到快速转移的目的. 记队列的头指针为h,尾指针为t. 对于队列的头部,如果slope[q[h],q[h+1]]<2*s[i],那么,q[h]一定可以去掉了.h=h+1. 事实上经过这样的调整后,q[h]就是i的最有决策,直接取来更新就是了. 更新出f[i]后,将f[i]从尾部加入队列,并用i去剔除无用决策. 对于队列的尾部,如果slope[q[t-1],q[t]]>slope[q[t],i],那么q[t]可以去掉.t=t-1. (这里我是按照我自己写程序的习惯写的,先用i去更新队尾,再加入i.还可以有不同的写法) 顺便说一句,这样维护以后,队列中的"点"形成一个上凸包(联想上面说的斜率). 程序大致过程 for i=1 to n do begin 当队列不为空时,更新队头; 取当前队头更新f[i]; 用i去更新队尾; 将i加入队尾. end; 可以看到外层循环是O(N)的,内层里每个元素进出队列仅一次,所以总效率为O(N). code:(HDU3507) const oo=1e100; maxn=500001; var s,f:Array[0..maxn] of int64; q:array[0..maxn] of longint; n,m,i,h,t,c:longint; function slope(j,k:longint):extended; begin if s[j]=s[k] then begin if f[j]>=f[k] then slope:=-oo else slope:=oo; exit; end; slope:=(f[j]-f[k]+s[j]*s[j]-s[k]*s[k])/(s[j]-s[k]); end; begin while not seekeof do begin readln(n,m); for i:=1 to n do begin readln(c); s[i]:=s[i-1]+c; end; h:=0; t:=0; for i:=1 to n do begin while (h<t)and(slope(q[h],q[h+1])<2*s[i]) do inc(h); f[i]:=f[q[h]]+(s[i]-s[q[h]])*(s[i]-s[q[h]])+M; while (h<t)and(slope(q[t-1],q[t])>slope(q[t],i)) do dec(t); inc(t); q[t]:=i; end; writeln(f[n]); end; end. Bzoj 1010 [hnoi2008]toy 题目大意:给n个数,求将这些数切成数段,每段的长度为(sum+(i-j+1)-l)^2,求总的长度和最小。 裸dp dp[i] := min(dp[k] + (f[i]-f[j]-c) 有 i<j,f[i] = sum[i] + I; c = l+1 把方程转化为 y=kx+ans,ans即我们要求的数,x,y,k通过枚举的j可知,所以在斜率一定的情况下,直线 k?+ans 第一个碰到的决策点即使ans最小。 然后通过斜率优化,可以证明决策点的最优,构建维护一个单调队列(点与点之间的斜率单调递增)(队尾维护),然后队首则维护首2点斜率大于k(k也可以推出随i增加单调的) {补充:单调队列维护下凸性,队首维护解决当前最优解,队尾维护则是删除上凸点} Dp[x] = min(dp[i]+(f[x]-f[i]-c)^2) =f[x]^2+min(dp[i]-2f[x](f[i]+c)+(f[i]+c)^2) 设 dp[x]-f[x]^2=G dp[i]+(f[i]+c)^2 = Ti 2(f[i]+c) = Hi 原式 = G = Ti –f[x]Hi 直线 = Ti = G+f[x]Hi 斜率 = Tj-Ti / Hj-Hi const oo=1<<60; var f,s,q:array[0..50001] of int64; n,l,i,j,c,h,t:longint; function min(a,b:int64):int64; begin if a>b then exit(b); exit(a); end; function slope(j,k:longint):extended; begin exit((f[j]-f[k]-sqr(s[k]+k)+sqr(s[j]+j))/(s[j]+j-s[k]-k)) end; begin readln(n,l); for i:=1 to n do begin readln(c); s[i]:=s[i-1]+c; end; h:=0; t:=0; for i:=1 to n do begin while (h<t)and(slope(q[h],q[h+1])<(i+s[i]-l-1)*2) do inc(h); f[i]:=f[q[h]]+sqr(i-q[h]-1+s[i]-s[q[h]]-l); while (h<t)and(slope(q[t-1],q[t])>slope(q[t],i)) do dec(t); inc(t); q[t]:=i; end; writeln(f[n]); end. APIO2010 特别行动队 【题目描述】 你有一支由 n 名预备役士兵组成的部队,士兵从1到n编号,要将他们拆分成若干特别行动队调入战场。出于默契的考虑,同一支特别行动队中队员的编号应该连续,即为形如(i, i + 1, …, i + k)的序列。 编号为 i 的士兵的初始战斗力为 xi ,一支特别行动队的初始战斗力 x为队内士兵初始战斗力之和,即 x = xi + xi+1 + … + xi+k。   通过长期的观察,你总结出一支特别行动队的初始战斗力 x将按如下经验公式修正为x':x' = ax^2 + bx + c,其中 a, b, c是已知的系数(a < 0)。   作为部队统帅,现在你要为这支部队进行编队,使得所有特别行动队修正后战斗力之和最大。试求出这个最大和。   例如, 你有4名士兵, x1 = 2, x2 = 2, x3 = 3, x4 = 4。经验公式中的参数为 a = –1, b = 10, c = –20。此时,最佳方案是将士兵组成 3个特别行动队:第一队包含士兵1和士兵2,第二队包含士兵3,第三队包含士兵 4。特别行动队的初始战斗力分别为4, 3, 4,修正后的战斗力分别为 4, 1, 4。修正后的战斗力和为 9,没有其它方案能使修正后的战斗力和更大。 【输入文件】 输入由三行组成。第一行包含一个整数 n,表示士兵的总数。第二行包含三个整数 a, b, c,经验公式中各项的系数。第三行包含 n 个用空格分隔的整数 x1, x2, …, xn,分别表示编号为1, 2, …, n的士兵的初始战斗力。 【输出文件】 输出一个整数,表示所有特别行动队修正后战斗力之和的最大值。 【输入样例】 4 -1 10 -20 2 2 3 4 【输出样例】 9 【数据范围】 20%的数据中,n ≤ 1000; 50%的数据中,n ≤ 10,000; 100%的数据中,1 ≤ n ≤ 1,000,000,–5 ≤ a ≤ –1,|b| ≤ 10,000,000,|c| ≤ 10,000,000,1 ≤ xi ≤ 100。 【题目分析】 首先看到题目就可以知道这是一道动态规划,然而朴素的n^2算法只能拿到20分。 首先,对于这个题来说,其决策是单调的,这样我们就可以用单调性把时间复杂度优化到nlogn,实践证明这样可以过7~8个点。 然后决策单调了,我们就会想到斜率…… 设对于f[i],由k决策更新比j决策更优,且k<j,那么有如下式子(si表示前i项和) F[j]+a*(si-sj)^2+b*(si-sj)+c<f[k]+a*(si-sk)^2+b*(si-sk)+c 转化过程略,最后可以化为如下式子: 2*a*si>[(s*sj^2-b*sj+f[j])-(a*sk^2-b*sk+f[k])]/(sj-sk) 设g[i]=a*si^2-b*si+f[i],那么我们就可以把si作为横坐标,g[i]作为纵坐标来表示斜率,这样就可以维护一个凸形的曲线,每次把队首斜率小于2*a*si的点出队,用队首的点计算f[i]和g[i],再用g[i]去维护队列曲线的凸形。 program test1; var s,f,g:array[0..1000000]of int64; d:array[0..1000000]of longint; t,w,i,j,n:longint; a,b,c:int64; function xl(i,j:longint):extended; begin exit((g[j]-g[i])/(s[j]-s[i])); end; begin readln(n); readln(a,b,c); for i:=1 to n do begin read(s[i]); inc(s[i],s[i-1]); end; t:=0;w:=0;d[0]:=0;g[0]:=0; for i:=1 to n do begin while (t<w)and(xl(d[t],d[t+1])>=2*a*s[i]) do inc(t); j:=d[t]; f[i]:=f[j]+a*sqr(s[i]-s[j])+b*(s[i]-s[j])+c; g[i]:=a*sqr(s[i])-b*s[i]+f[i]; while (w>t)and(xl(d[w],i)>xl(d[w-1],d[w])) do dec(w); inc(w); d[w]:=i; end; writeln(f[n]); end. 第二种题解: const oo=2000000000; var q,num:array[0..1000001] of longint; f,s:array[0..1000001] of extended; n,i,h,t:longint; w,a,b,c:extended; function slope(j,k:longint):extended; begin exit((f[j]-f[k]+a*s[j]*s[j]-a*s[k]*s[k]-b*s[j]+b*s[k])/(s[j]-s[k])) end; begin readln(n); readln(a,b,c); for i:=1 to n do begin read(num[i]); s[i]:=s[i-1]+num[i]; end; h:=0; t:=0; for i:=1 to n do begin while (h<t)and(slope(q[h],q[h+1])>=2*a*s[i]) do inc(h); w:=s[i]-s[q[h]]; f[i]:=f[q[h]]+a*w*w+b*w+c; while (h<t)and(slope(q[t-1],q[t])<=slope(q[t],i)) do dec(t); inc(t); q[t]:=i; end; writeln(f[n]:0:0); end. 特别行动队 (亚洲与太平洋地区信息学奥林匹克竞赛) 你有一支由 n 名预备役士兵组成的部队,士兵从 1 到 n 编号,要将他们拆分成若干特别行动队调入战场。出于默契的考虑,同一支特别行动队中队员的编号应该连续,即为形如(i, i + 1, …, i + k)的序列。编号为 i 的士兵的初始战斗力为 xi ,一支特别行动队的初始战斗力 x 为队内士兵初始战斗力之和,即 x = xi + xi+1 + … + xi+k。通过长期的观察,你总结出一支特别行动队的初始战斗力 x 将按如下经验公式修正为 x':x' = ax2 + bx + c,其中 a, b, c 是已知的系数(a < 0)。作为部队统帅,现在你要为这支部队进行编队,使得所有特别行动队修正后战斗力之和最大。试求出这个最大和。 例如,你有 4 名士兵,x1 = 2, x2 = 2, x3 = 3, x4 = 4。经验公式中的参数为 a = –1,b = 10, c = –20。此时,最佳方案是将士兵组成 3 个特别行动队:第一队包含士兵1 和士兵 2,第二队包含士兵 3,第三队包含士兵 4。特别行动队的初始战斗力分别为 4, 3, 4,修正后的战斗力分别为 4, 1, 4。修正后的战斗力和为 9,没有其它方案能使修正后的战斗力和更大。 【输入格式】 输入由三行组成。第一行包含一个整数 n,表示士兵的总数。第二行包含三 个整数 a, b, c,经验公式中各项的系数。第三行包含 n 个用空格分隔的整数 x1,x2, …, xn,分别表示编号为 1, 2, …, n 的士兵的初始战斗力。 【输出格式】 输出一个整数,表示所有特别行动队修正后战斗力之和的最大值。 【样例输入】 4 -1 10 -20 2 2 3 4 【数据范围】 20%的数据中,n ≤ 1000; 50%的数据中,n ≤ 10,000; 【样例输出】 9 100%的数据中,1 ≤ n ≤ 1,000,000,–5 ≤ a ≤ –1,|b| ≤ 10,000,000,|c| ≤10,000,000,1 ≤ xi ≤ 100。 此题DP方程很容易想出来,f[i]为前i个士兵的最大值,f[i]:=max(f[j]+a*t^2+b*t+c) t:=s[i]-s[j],s是前缀和但是由于时间复杂度为O(N^2),需要进行优化。 考试的时候我用的是一个小优化,但是效果很显著,过了8组, 由方程可知,函数由f[j]+h[j]组成,而h[i]又与i有关,所以不能之间单调队列, 我想的是h[j]取得最大的时候是s[j]最接近s[i]+b/(2*a)的时候, 所以当j<k(s[j]<s[k])且f[j]<f[k]那么j就没k优 只用记录一下上一次的j值,这一次从j开始搜 第二种就是斜率优化。 由f[j]+h[j]>f[k]+h[k]可得到 (f[j]-f[k]+a*(sqr(s[j])-sqr(s[k]))+b*(s[k]-s[j]))/(s[j]-s[k])<2*a*s[i] 这样我们成功地排除掉了s[i]的干扰。然后我们可以维护一个队列, 设x[j,k]=(f[j]-f[k]+a*(sqr(s[j])-sqr(s[k]))+b*(s[k]-s[j]))/(s[j]-s[k]) 使队列中的2*a*s[i]>x[i,i+1]>x[i+1,i+1]>...... 然后每次到i的时候维护一下队列,队首即为最优。然后在维护一下队尾,保持其单调性即可。 第一种优化: program commando; var n,i,j,k,p,x:longint; t,a,b,c,q:extended; s:array[0..1000000] of extended; //extended在32位运算速度>int64 f:array[0..1000000] of extended; begin assign(input,'commando.in'); reset(input); assign(output,'commando2.out'); rewrite(output); read(n); read(a,b,c); for i:=1 to n do begin read(x); s[i]:=s[i-1]+x; end; for i:=1 to n do f[i]:=-100000000; f[0]:=0; //初值 p:=0; for j:=1 to n do for k:=p to j-1 do begin t:=s[j]-s[k]; q:=a*t*t+b*t+c; if f[j]<f[k]+q then begin f[j]:=f[k]+q; p:=k; end; end; writeln(f[n]:0:0); close(input); close(output); end. 第二种优化 program commando2; //单调性优化 {$inline on} var n,i,x,l,r:longint; t,a,b,c,k:extended; f,s:array[0..1000000] of extended; dui:array[0..1000000] of longint; function slope(j,k:longint):extended; inline; begin slope:=(f[j]-f[k]+a*(sqr(s[j])-sqr(s[k]))+b*(s[k]-s[j])){/(s[j]-s[k])};{除法变乘法更快} end; begin assign(input,'commando.in'); reset(input); assign(output,'commando.out'); rewrite(output); read(n); read(a,b,c); for i:=1 to n do begin read(x); s[i]:=s[i-1]+x; end; fillchar(f,sizeof(f),200); //要赋初值,中间点可能乘下来为负 f[0]:=0; l:=0; r:=1; dui[1]:=0; for i:=1 to n do begin t:=2*a*s[i]; while (l<r-1)and(slope(dui[l+1],dui[l+2])<=t*(s[dui[l+1]]-s[dui[l+2]])) do inc(l); //不满足的出队 k:=s[i]-s[dui[l+1]]; f[i]:=f[dui[l+1]]+a*k*k+b*k+c; while (l<r-1)and(slope(dui[r-1],dui[r])*(s[dui[r]]-s[i])<=slope(dui[r],i)*(s[dui[r-1]]-s[dui[r]])) do dec(r); //不为最优的出队 inc(r); dui[r]:=i; end; writeln(f[n]:0:0); close(input); close(output); end. 锯木场选址 (CEOI2004) [题目描述] 从山顶上到山底下沿着一条直线种植了n棵老树。当地的政府决定把他们砍下来。为了不浪费任何一棵木材,树被砍倒后要运送到锯木厂。木材只能按照一个方向运输:朝山下运。山脚下有一个锯木厂。另外两个锯木厂将新修建在山路上。你必须决定在哪里修建两个锯木厂,使得传输的费用总和最小。假定运输每公斤木材每米需要一分钱。 任务 你的任务是写一个程序: 从标准输入读入树的个数和他们的重量与位置 计算最小运输费用 将计算结果输出到标准输出 输入 输入的第一行为一个正整数n——树的个数(2≤n≤20 000)。树从山顶到山脚按照1,2……n标号。 接下来n行,每行有两个正整数(用空格分开)。 第i+1行含有:wi——第i棵树的重量(公斤为单位)和 di——第i棵树和第i+1棵树之间的距离,1≤wi ≤10 000,0≤di≤10 000。最后一个数dn,表示第n棵树到山脚的锯木厂的距离。 保证所有树运到山脚的锯木厂所需要的费用小于2000 000 000分。 输出 输出只有一行一个数:最小的运输费用。 样例输入 9 1 2 2 1 3 3 1 1 3 2 1 6 2 1 1 2 1 1 样例输出 26 Const maxn=20001; var f,w,d,sw,sd,c,q:array[0..maxn] of longint; n,i,j,tmp,ans,h,t:longint; function cost(l,r:longint):longint; begin cost:=c[r]-c[l-1]-sw[l-1]*(sd[r]-sd[l-1]); end; function slope(j,k:longint):extended; begin slope:=(sw[k]*sd[k]-sw[j]*sd[j])/(sw[k]-sw[j]); end; begin readln(n); for i:=1 to n do readln(w[i],d[i]); for i:=1 to n+1 do begin sw[i]:=sw[i-1]+w[i]; sd[i]:=sd[i-1]+d[i-1]; end; for i:=1 to n+1 do c[i]:=c[i-1]+sw[i-1]*d[i-1]; h:=1; t:=1; q[1]:=1; for i:=2 to n do begin while (h<t)and(slope(q[h],q[h+1])<sd[i]) do inc(h); f[i]:=c[q[h]]+cost(q[h]+1,i)+cost(i+1,n+1); while (h<t)and(slope(q[t-1],q[t])>slope(q[t],i)) do dec(t); inc(t); q[t]:=i; end; ans:=maxlongint; for i:=2 to n do if ans>f[i] then ans:=f[i]; writeln(Ans); end. Poj1180 题目大意 :给定n个工作,可以任意分组,最后每个工作的花费是O[i]*f[i],其中O[i]是i所在分组整体被完成的时间,给定开始时间,机器启动时间S,求完成所有任务最小花费。 算法 :动态规划 + 斜率优化 思路 :首先想到了dp[i] = min{dp[j] + (S + O[j] + sum[i] – sum[j]) * f[i] ) (j < i)但是这是二维的方程,需要优化成一维,但是这个式子很难化解成f[i] – f[j] = k (g[i] – g[j]) + b的形式,而且如果将j和i分在一组,O[j]的值也会改变,无法用斜率搞,最后看了网上大牛才知,设定状态 Dp[i] = min{dp[j] + (S + sumt[i] – sumt[j] ) * sumf[i] {sumt[i] =t[i] + t[i + 1]…….}, sumf[i] = f[i] + f[i + 1]…. 然后化解这个式子就能斜率优化了。这里处理O[i]也算是一个技巧了,将由工作i导致的i之后的花费加到i上,这样每次的开始时间都成为了0,从后往前dp即可,其他都一样。 var f,tx,fx,st,sf,q:array[0..100001] of longint; n,s,i,h,t:longint; function slope(i,j:longint):extended; begin exit((f[i]-f[j])/(st[i]-st[j])); end;begin readln(n); readln(s); for i:=1 to n do readln(tx[i],fx[i]); for i:=n downto 1 do begin st[i]:=st[i+1]+tx[i]; sf[i]:=sf[i+1]+fx[i]; end; h:=0; t:=0; for i:=n downto 1 do begin while (h<t)and(slope(q[h],q[h+1])<sf[i]) do inc(h); f[i]:=f[q[h]]+(s+st[i]-st[q[h]])*sf[i]; while (h<t)and(slope(q[t-1],q[t])>slope(q[t],i)) do dec(t); inc(t); q[t]:=i; end; writeln(f[1]);end. poj 3709 题意是给你一个n长度递增数列,将其分组,每组不少于m个,每组的cost是每组中所有元素减去里面最小元素的值的总和,要求你算最小的cost。我想说这类的分组问题一般都是dp解决的,这题也不例外,dp状态也很好设定,dp[i]表示前i个元素的cost最小值,当然是已经分好组了,因为没限定你要分几组就是一维的状态,但是把状态方程列出来后就会发现一个问题,状态转移方程dp[i]=dp[tem]+sum[i]-sum[tem]-(i-tem)*a[tem+1];m<tem<i;这个复杂度是n*mn<500000,m<n,显然超时,这时就要用到斜率+单调队列优化,我也是刚学,研究了好久才明白怎么做的,大意就是再队列中维护一个单调的斜率,详情不介绍了,可以baidu一下,很多资料,有了这个一下子就把复杂度降到了o(n),很快啊,二维的斜率优化就是用四边形不等式。这里需要说一个细节if(!(G(x,y)*S(y,z)<G(y,z)*S(x,y)))这个条件是保证斜率单调,之前sb的写了好多条件都wa了。还有中间会溢出,要用longlong啊。 Var q:array[0..500001] of longint; f,s,num:array[0..500001] of extended; dnum,d,i,j,m,n,h,t:longint; function slope(j,k:longint):extended; var x,y:extended; begin y:=f[j]-f[k]-s[j]+s[k]+num[j+1]*j-num[k+1]*k; x:=num[j+1]-num[k+1]; if x=0 then if y>=0 then exit(k+m) else exit(n+1); slope:=y/x; if slope<k+m then exit(k+m); end; begin readln(dnum); for d:=1 to dnum do begin readln(n,m); fillchar(s,sizeof(s),0); fillchar(f,sizeof(f),0); for i:=1 to n do begin read(num[i]); s[i]:=s[i-1]+num[i]; end; readln; h:=0; t:=0; for i:=m to n do begin while (h<t)and(slope(q[h],q[h+1])<=i) do inc(h); f[i]:=f[q[h]]+s[i]-s[q[h]]-num[q[h]+1]*(i-q[h]); while (h<t)and(slope(q[t-1],q[t])>=slope(q[t],i)) do dec(t); inc(t); q[t]:=i; end; writeln(f[n]:0:0); end; end. Poj2018 【问题描述】 题意很简单,就是给你n个数,求一个连续数串的平均值最大,数串长度不小于F n<=100000 【分析】 在不考虑数据范围的情况下,可以很容易地写出O(n^2)的动规方程,f[i]=max{(sum[i]-sum[j-1])/(i-j+1)} 如果我们把sum的图像画出来,那么我们发
展开阅读全文

开通  VIP会员、SVIP会员  优惠大
下载10份以上建议开通VIP会员
下载20份以上建议开通SVIP会员


开通VIP      成为共赢上传

当前位置:首页 > 教育专区 > 其他

移动网页_全站_页脚广告1

关于我们      便捷服务       自信AI       AI导航        抽奖活动

©2010-2025 宁波自信网络信息技术有限公司  版权所有

客服电话:4009-655-100  投诉/维权电话:18658249818

gongan.png浙公网安备33021202000488号   

icp.png浙ICP备2021020529号-1  |  浙B2-20240490  

关注我们 :微信公众号    抖音    微博    LOFTER 

客服