HGOI20181031 模拟题解
sol:第一题就DP?!然后写了O(n^2) dp再考虑优化!!!(尽量部分分带上!!!)
我写了正确的dp然后优化错了,具体的dp方法是考虑到对于右侧到左侧他是没有后效性的
所以定义f[i]为i及以后最大的代价和,对于合法的j,转移f[i]=max{f[j]+P[i]},j需要满足a[i]+x[i]<a[j],j>=i
由于给出的a[i]递增然后我只要往i的右侧找到第一个合法的j然后转移就行了,复杂度O(n log n)
我错在了用堆来优化,然后把后面的删掉了,其实可以再前面的从被误删的东西转移而来。
code:
# include <bits/stdc++.h> # ifdef O_2 # pragma GCC optimze(2) # endif # define int long long using namespace std; const int MAXN=1e5+10; int f[MAXN],a[MAXN],x[MAXN],p[MAXN]; int n; inline int read() { int X=0,w=0;char c=0; while (!(c>='0'&&c<='9')) w|=c=='-',c=getchar(); while (c>='0'&&c<='9') X=(X<<1)+(X<<3)+(c^48),c=getchar(); return w?-X:X; } inline void write(int x) { if (x<0) { x=-x;putchar('-');} if (x>9) write(x/10); putchar('0'+x%10); } inline void writeln(int x) { write(x);putchar('\n');} signed main() { n=read(); for (int i=1;i<=n;i++) a[i]=read(),p[i]=read(),x[i]=read(); f[n]=p[n]; for (int i=n-1;i>=1;i--) { f[i]=f[i+1]; int j=upper_bound(a+i+1,a+1+n,a[i]+x[i])-a; f[i]=max(max(f[i],p[i]),f[j]+p[i]); } writeln(f[1]); return 0; }
sol:这道题目对于100%的数据n,m<=3000,显然发现这一定是O(n2)的算法,
然后如果对于X1到X2的最短路径设为R1,X3到X4最短路劲R2,要求R1和R2交的尽可能多,那么这个解一定更优
首先一定要在最短路上,其次要求R1和R2尽可能交的更多,我们不妨设刚开始交的地方设为i,交结束的地方设为j
我们先求出X1,X2,X3,X4到各点的最短路D1,D2,D3,D4
我们枚举i然后再枚举j 由上图可以看出就是D1[i]+D2[j]+D3[i]+D4[j]+dist(i,j)在枚举j之前我们可以O(n)求出i的最短路D5
那么就是最小化D1[i]+D2[j]+D3[i]+D4[j]+D5[j],
然后我们交换(X1,X2)or (X3,X4) 之中的任意一对然后再求min,就是D1[i]+D2[j]+D3[j]+D4[i]+D5[j],
然后对于每一次枚举Ans=Min(D1[i]+D2[j]+D3[i]+D4[j]+D5[j],D1[i]+D2[j]+D3[j]+D4[i]+D5[j],ans)
对于一个显然的情况我们最后特判就是直接 X1走到X2,X3 走到 X4 最短路虽然并没有重复的路 即 ans=Min(ans,D1[X2]+D3[X4]);
code:
# include <bits/stdc++.h> # ifdef O_2 # pragma GCC optimze(2) # endif using namespace std; const int MAXN=3005; int n,m,X1,X2,X3,X4; int D1[MAXN],D2[MAXN],D3[MAXN],D4[MAXN],D5[MAXN]; int tot=0,head[MAXN]; bool vis[MAXN]; struct rec{ int pre,to,w;}a[MAXN*2]; inline int read() { int X=0,w=0;char c=0; while (!(c>='0'&&c<='9')) w|=c=='-',c=getchar(); while (c>='0'&&c<='9') X=(X<<1)+(X<<3)+(c^48),c=getchar(); return w?-X:X; } inline void write(int x) { if (x<0) { x=-x;putchar('-');} if (x>9) write(x/10); putchar('0'+x%10); } inline void writeln(int x) { write(x);putchar('\n');} void adde(int u,int v,int w) { a[++tot].pre=head[u]; a[tot].to=v; a[tot].w=w; head[u]=tot; } struct node{ int id,dist;}; int d[MAXN]; queue<node>q; void bfs(int s) { memset(vis,false,sizeof(vis)); memset(d,0x3f,sizeof(d)); d[s]=0; vis[s]=1; q.push((node){s,0}); while (!q.empty()) { node u=q.front();q.pop(); for (int i=head[u.id];i;i=a[i].pre) { int v=a[i].to; if (vis[v]) continue; vis[v]=1; d[v]=u.dist+1; q.push((node){v,d[v]}); } } } int Min(int a,int b,int c) { if (b<a) a=b; if (c<a) a=c; return a; } int main() { n=read();m=read(); X1=read();X2=read();X3=read();X4=read(); int u,v; for (int i=1;i<=m;i++) { u=read();v=read(); adde(u,v,1); adde(v,u,1); } bfs(X1); memcpy(D1,d,sizeof(d)); bfs(X2); memcpy(D2,d,sizeof(d)); bfs(X3); memcpy(D3,d,sizeof(d)); bfs(X4); memcpy(D4,d,sizeof(d)); int ans=m; for (int i=1;i<=n;i++) { bfs(i); memcpy(D5,d,sizeof(d)); for (int j=1;j<=n;j++) ans=Min(ans,D1[i]+D3[i]+D2[j]+D4[j]+D5[j],D1[i]+D4[i]+D3[j]+D2[j]+D5[j]); } ans=min(ans,D1[X2]+D3[X4]); writeln(ans); return 0; }