1、rqnoj82:又上锁妖塔
很简单的DP,以层数和能否用法术做状态来递推,注意最后的答案有可能在n+1层
代码:
#include<cstdio> #include<cstring> using namespace std; const int maxn = 10000 + 10; int n; int f[maxn][2]; int l[maxn]; void init() { freopen("rqnoj82.in","r",stdin); freopen("rqnoj82.out","w",stdout); } void readdata() { scanf("%d",&n); for(int i = 1;i <= n;i++) { scanf("%d",&l[i]); } } int min(int a,int b) { return a < b ? a : b; } void solve() { memset(f,0,sizeof(f)); for(int i = 1;i <= n + 1;i++) { if(i == 1) f[i][0] = 0; else f[i][0] = min(f[i-1][1],f[i-2][1]); f[i][1] = min(f[i-1][0],f[i-1][1]) + l[i]; } int ans1 = min(f[n][0],f[n][1]); int ans = min(ans1,f[n+1][0]); printf("%d",ans); } int main() { init(); readdata(); solve(); return 0; }
2、rqnoj73:展演队形
f[i][j]表示一共有i人最后一排有j人的方案数,所以只要枚举最后一排的人数就可以递推出答案。
代码:
#include<cstdio> #include<cstring> using namespace std; const int maxn = 150; int n; int f[maxn][maxn]; void init() { freopen("rqnoj73.in","r",stdin); freopen("rqnoj73.out","w",stdout); } void readdata() { scanf("%d",&n); } void solve() { for(int i = 1;i <= n;i++) { f[i][i] = 1; } for(int i = 2;i <= n;i++) for(int j = 1;j < i;j++) { for(int k = 1;k < j;k++) { f[i][j] += f[i-j][k]; } } long long ans = 0; for(int i = 1;i < n;i++) { ans += f[n][i]; } printf("%I64d",ans); } int main() { init(); readdata(); solve(); return 0; }
3、rqnoj93:吃西瓜
求最大子立方,通过降维的思想可以很顺利的求出来。
代码:
#include<cstdio> #include<cstring> using namespace std; const int maxh = 35; const int maxn = 50 + 10; int mat[maxh][maxn][maxn]; int f[maxh][maxn][maxn]; int ans = 0; int h,m,n; void init() { freopen("rqnoj93.in","r",stdin); freopen("rqnoj93.out","w",stdout); } void readdata() { scanf("%d%d%d",&h,&m,&n); for(int i = 1;i <= h;i++) { for(int j = 1;j <= m;j++) { for(int k = 1;k <= n;k++) { scanf("%d",&mat[i][j][k]); } } } } int getsum1(int a[]) { int sum = 0,f = 0; for(int i = 1;i <= n;i++) { if(f > 0) f += a[i]; else f = a[i]; if(f > sum)sum = f; } return sum; } int getsum2(int a[maxn][maxn]) { int sum = 0,max = 0; int f[maxn]; for(int i = 1;i <= m;i++) { memset(f,0,sizeof(f)); for(int j = i;j <= m;j++) { for(int k = 1;k <= n;k++) f[k] += a[j][k]; max = getsum1(f); if(max > sum)sum = max; } } return sum; } int getsum3(int a[maxn][maxn][maxn]) { int max = 0,sum = 0; int f[maxn][maxn]; for(int i = 1;i <= h;i++) { memset(f,0,sizeof(f)); for(int j = i;j <= h;j++) { for(int k = 1;k <= m;k++) for(int t = 1;t <= n;t++) { f[k][t] += a[j][k][t]; } max = getsum2(f); if(max > sum)sum = max; } } return sum; } void solve() { printf("%d",getsum3(mat)); } int main() { init(); readdata(); solve(); return 0; }
4、rqnoj94:飙车
这道题比较有趣,主要是掌握好相对位置,相当于原车的速度为2,只要设计好状态就能做出来了。
代码:
#include<cstdio> #include<cstring> using namespace std; const int maxl = 200 + 10; const int maxk = 10 + 10; const int inf = 0x7fffffff; int k,l; bool map[maxl][maxk]; int f[maxl][maxk]; void init() { freopen("rqnoj94.in","r",stdin); freopen("rqnoj94.out","w",stdout); } void readdata() { memset(map,false,sizeof(map)); scanf("%d%d\n",&l,&k); for(int i = l;i >= 1;i--) { for(int j = 1;j <= k;j++) { char t; scanf("%c",&t); if(t == '1') { map[i][j] = true; } } scanf("\n"); } } int cost(int x,int i,int j) { int cou = 0; if(x == 1) { if(map[i*2][j])++cou; if(map[i*2-1][j])++cou; return cou; } if(x == 2) { if(map[i*2][j])++cou; return cou; } } int min(int a,int b) { return a < b ? a : b; } void solve() { memset(f,0x7f,sizeof(f)); for(int i = 1;i <= k;i++) { f[0][i] = 0; } for(int i = 1;i <= l + 1;i++) { for(int j = 1;j <= k;j++) { f[i][j] = min(f[i][j],f[i-1][j] + cost(1,i,j)); if(j > 1) { f[i][j] = min(f[i][j],f[i-1][j-1] + cost(2,i,j)); } if(j < k) { f[i][j] = min(f[i][j],f[i-1][j+1] + cost(2,i,j)); } } } int ans = inf; for(int i = 1;i <= k;i++) { if(f[l][i] < ans) { ans = f[l + 1][i]; } } printf("%d",ans); } int main() { init(); readdata(); solve(); return 0; }
5、rqnoj99:配置魔药
据说是多线程DP。用f[i][j][k]表示第i个物品,第一个坩埚到时间j,第二个坩埚到时间k得到的最大价值。
#include<cstdio> #include<cstring> #include<cstdlib> using namespace std; const int maxt = 500 + 10; const int maxn = 100 + 10; struct tnode { int l,r; int w; }medi[maxn]; int f[maxn][maxt][maxt]; int t,n; void init() { freopen("rqnoj99.in","r",stdin); freopen("rqnoj99.out","w",stdout); } int cmp(const void *a,const void *b) { return (*(tnode *)a).l - (*(tnode *)b).l; } void readdata() { scanf("%d%d",&t,&n); for(int i = 1;i <= n;i++) { scanf("%d%d%d",&medi[i].l,&medi[i].r,&medi[i].w); } } int max(int a,int b) { return a > b ? a : b; } void solve() { qsort(&medi[1],n,sizeof(medi[0]),cmp); for(int i = 1;i <= n;i++) { for(int j = 0;j <= t;j++) { for(int k = 0;k <= t;k++) { f[i][j][k] = f[i-1][j][k]; if(j >= medi[i].r) { f[i][j][k] = max(f[i][j][k],f[i-1][medi[i].l-1][k] + medi[i].w); } if(k >= medi[i].r) { f[i][j][k] = max(f[i][j][k],f[i-1][j][medi[i].l-1] + medi[i].w); } } } } printf("%d",f[n][t][t]); } int main() { init(); readdata(); solve(); return 0; }
6、rqnoj105:核电站问题
对于每个位置i,只有放和不放两种状态,所以用f[i][0]表示第i个位置不放的方案数,f[i][1]表示第i位置放的方案数,所以如果i - m >= 0,f[i][1] = f[i-1][0] + f[i-1][1] - f[i-m][0]
代码:
#include<cstdio> #include<cstring> using namespace std; const int maxn = 50 + 10; int n,m; long long f[maxn][2]; void init() { freopen("rqnoj105.in","r",stdin); freopen("rqnoj105.out","w",stdout); } void readdata() { scanf("%d%d",&n,&m); } void solve() { memset(f,0,sizeof(f)); f[0][0] = 1; for(int i = 1;i <= n;i++) { f[i][0] = f[i-1][0] + f[i-1][1]; if(i - m >= 0) { f[i][1] = f[i-1][0] + f[i-1][1] - f[i-m][0]; } else { f[i][1] = f[i-1][0] + f[i-1][1]; } } long long ans = f[n][0] + f[n][1]; printf("%I64d",ans); } int main() { init(); readdata(); solve(); return 0; }
The End...