数据结构没什么好写的。。分块和整体二分还有点分学得很懂。。果然我还是比较适合这些东西
poj2279 奇怪题,我的想法就是五维记录最边上的一斜排,会M,结果的的确确是锻炼思维的,正解并不是DP2333
LCIS 这个。。。其实还挺常规的吧(脑子一抽),f[i][j]表示第一个匹配到i第二个匹配到j且选了j。
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; int a[3100],b[3100],f[3100][3100]; int main() { int n; scanf("%d",&n); for(int i=1;i<=n;i++)scanf("%d",&a[i]); for(int i=1;i<=n;i++)scanf("%d",&b[i]); for(int i=1;i<=n;i++) { int mx=0; for(int j=1;j<=n;j++) { if(a[i]!=b[j])f[i][j]=f[i-1][j]; else f[i][j]=mx+1; if(b[j]<a[i])mx=max(mx,f[i-1][j]); } } int ans=0; for(int j=1;j<=n;j++)ans=max(ans,f[n][j]); printf("%d ",ans); return 0; }
poj3666 首先要证明的是一定存在一种构造b的方案令所有b值都在a中出现过(我就不证了),f[i][j]表示枚举到i,且当前等于a数组中排名为j的那个数的最小值,和上题一样可以省掉一个for(也是常规操作吧)
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; typedef long long LL; int n,m; LL a[2100],ls[2100]; void LSH() { m=0; for(int i=1;i<=n;i++)ls[++m]=a[i]; sort(ls+1,ls+m+1); m=unique(ls+1,ls+m+1)-ls-1; for(int i=1;i<=n;i++) a[i]=lower_bound(ls+1,ls+m+1,a[i])-ls; } LL ans; LL f[2100][2100]; LL myabs(LL x){return x>0?x:-x;} void DP1() { memset(f,63,sizeof(f)); for(int j=1;j<=n;j++)f[1][j]=myabs(ls[a[1]]-ls[j]); for(int i=2;i<=n;i++) { LL mn=(1LL<<62); for(int j=1;j<=m;j++) { mn=min(mn,f[i-1][j]); f[i][j]=mn+myabs(ls[a[i]]-ls[j]); } } for(int j=1;j<=n;j++)ans=min(ans,f[n][j]); } void DP2() { memset(f,63,sizeof(f)); for(int j=1;j<=n;j++)f[1][j]=myabs(ls[a[1]]-ls[j]); for(int i=2;i<=n;i++) { LL mn=(1LL<<62); for(int j=m;j>=1;j--) { mn=min(mn,f[i-1][j]); f[i][j]=mn+myabs(ls[a[i]]-ls[j]); } } for(int j=1;j<=n;j++)ans=min(ans,f[n][j]); } int main() { scanf("%d",&n); for(int i=1;i<=n;i++)scanf("%lld",&a[i]); LSH(); ans=(1LL<<62); DP1();DP2(); printf("%lld ",ans); return 0; }
Mobile Service 这个省维的思想还挺好的,因为要修第i-1个位置,那么当要修第i个位置的时候肯定有个人在p[i-1]省去一维
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; int mp[210][210],p[1100]; int f[1100][210][210]; int main() { int n,Q; scanf("%d%d",&n,&Q); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) scanf("%d",&mp[i][j]); p[0]=1; for(int i=1;i<=Q;i++)scanf("%d",&p[i]); memset(f,63,sizeof(f));f[0][2][3]=f[0][3][2]=0; for(int i=0;i<Q;i++) { for(int j=1;j<=n;j++) if(j!=p[i]) for(int k=1;k<=n;k++) if(k!=p[i]&&k!=j) if(f[i][j][k]<=999999999) { f[i+1][j][k]=min(f[i+1][j][k],f[i][j][k]+mp[p[i]][p[i+1]]); f[i+1][p[i]][k]=f[i+1][k][p[i]]=min(f[i+1][p[i]][k],f[i][j][k]+mp[j][p[i+1]]); f[i+1][p[i]][j]=f[i+1][j][p[i]]=min(f[i+1][p[i]][j],f[i][j][k]+mp[k][p[i+1]]); } } int ans=2147483647; for(int j=1;j<=n;j++) for(int k=1;k<=n;k++) ans=min(ans,f[Q][j][k]); printf("%d ",ans); return 0; }
传纸条 表示我一眼插头DP 然而就是大力DP就好,只用三维,因为只能下或右走那么当前两条线的位置肯定是在一条右往左的斜线上,也就是x1+y1=x2+y2
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; int a[60][60]; int f[110][60][60]; int main() { int n,m; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) scanf("%d",&a[i][j]); memset(f,0,sizeof(f));f[1][2][1]=a[1][2]+a[2][1]; for(int i=1;i<n+m-2;i++) { for(int x1=2;x1<=m;x1++) { int y1=i+2-x1; if(y1<=n) { for(int x2=1;x2<=x1-1;x2++) { int y2=i+2-x2; if(y2<=n) { if(y1+1<=n&&y2+1<=n)f[i+1][x1][x2]=max(f[i+1][x1][x2],f[i][x1][x2]+a[y1+1][x1]+a[y2+1][x2]); if(x1+1<=m&&x2+1<=m)f[i+1][x1+1][x2+1]=max(f[i+1][x1+1][x2+1],f[i][x1][x2]+a[y1][x1+1]+a[y2][x2+1]); if(y1+1<=n&&x2+1<=m&&(x2+1<x1||i==n+m-3))f[i+1][x1][x2+1]=max(f[i+1][x1][x2+1],f[i][x1][x2]+a[y1+1][x1]+a[y2][x2+1]); if(x1+1<=m&&y2+1<=n)f[i+1][x1+1][x2]=max(f[i+1][x1+1][x2],f[i][x1][x2]+a[y1][x1+1]+a[y2+1][x2]); } } } } } printf("%d ",f[n+m-2][m][m]); return 0; }
I-country 超麻烦,需要考虑行数,左右边界,当前权,当前左右区间分别是上升还是下降