zoj 3798 Abs Problem(数学:推理+滚动数组)
2014-08-24 20:03
399 查看
题意是给定n个数,定义一种运算为每次取当前数和下一个数的差的绝对值作为下一次运算的当前数
输出最小值,最大值以及对应的路径
感觉很犀利的一道题,但是比赛的时候AC率特别高...
我用了一个多小时才写出来,刚开始就想出来了递推步骤
受这几天刷的题的影响吧,第一反应是打表保存结果
我用vector保存,结果把我的电脑都跑死机了
开机后就想到了用一维数组即滚动数组优化来写
先说下分析过程:
令minv[i], maxv[i]分别保存i对应的最小值和最大值
不难想到:
那么这种思路对不对呢?观察下面的例子:
例如i==2时
minv[2] : 1 2
maxv[2]: 1 2
i == 3时
minv[3]: 1 2 3(错误!正确排列应该为:1 3 2)
maxv[3]: 1 2 3
所以求minv[i]时我们还要比较以下两种排列的大小:
minv[i-1]的前 i-1 项排列 + i
minv[i-1]的前 i-2 项排列 + i-1 + i
而对于maxv[i]则不需要额外的判定,只需在minv[i-1]的排列后+i即可
前8项的排列如下:
观察规律还可以发现最小值非0即1(与n*(n+1)/2 的奇偶性有关)
同样最大值非i即i-1(与n*(n-1)/2的奇偶性有关)
唯一的难点就在于打印路径了
我是用滚动数组的方法做的
不太好解释,直接看代码吧
代码如下:
输出最小值,最大值以及对应的路径
感觉很犀利的一道题,但是比赛的时候AC率特别高...
我用了一个多小时才写出来,刚开始就想出来了递推步骤
受这几天刷的题的影响吧,第一反应是打表保存结果
我用vector保存,结果把我的电脑都跑死机了
开机后就想到了用一维数组即滚动数组优化来写
先说下分析过程:
令minv[i], maxv[i]分别保存i对应的最小值和最大值
不难想到:
maxv[i] = i - minv[i-1] minv[i] = i -maxv[i-1]
那么这种思路对不对呢?观察下面的例子:
例如i==2时
minv[2] : 1 2
maxv[2]: 1 2
i == 3时
minv[3]: 1 2 3(错误!正确排列应该为:1 3 2)
maxv[3]: 1 2 3
所以求minv[i]时我们还要比较以下两种排列的大小:
minv[i-1]的前 i-1 项排列 + i
minv[i-1]的前 i-2 项排列 + i-1 + i
而对于maxv[i]则不需要额外的判定,只需在minv[i-1]的排列后+i即可
前8项的排列如下:
观察规律还可以发现最小值非0即1(与n*(n+1)/2 的奇偶性有关)
同样最大值非i即i-1(与n*(n-1)/2的奇偶性有关)
唯一的难点就在于打印路径了
我是用滚动数组的方法做的
不太好解释,直接看代码吧
代码如下:
#include <bits/stdc++.h> #define MAXN 60010 #define LL long long using namespace std; int n; int minv[MAXN], maxv[MAXN]; vector<LL> res_min, res_max; void init(int n) { res_min.clear(); res_max.clear(); minv[1] = maxv[1] = 1; res_min.push_back(1); res_max.push_back(1); for(LL i=2; i<=n; ++i) { LL tmp = i*(i+1)/2; if(tmp % 2) minv[i] = 1; else minv[i] = 0; tmp -= i; if(tmp % 2) maxv[i] = i-1; else maxv[i] = i; //printf("maxv[%d] = %d\n", i, maxv[i]); if(i%2) { if(i-maxv[i-1] > 1) { res_min[i-2] = i; res_min.push_back(i-1); } else res_min.push_back(i); res_max.push_back(i); } else { if(i-maxv[i-1] > 1) { res_max[i-2] = i; res_max.push_back(i-1); } else res_max.push_back(i); res_min.push_back(i); } } } int main(void) { while(scanf("%d", &n) != EOF) { init(n); printf("%d %d\n", minv , maxv ); if(n%2)//i为奇数时,res_minv[i]中保存的是最小排列,反之res_maxv[i]中保存的是最小排列 for(int i=0; i<n; ++i) printf("%lld ", res_min[i]); puts(""); for(int i=0; i<n; ++i) printf("%lld ", res_max[i]); puts(""); } else { for(int i=0; i<n; ++i) printf("%lld ", res_max[i]); puts(""); for(int i=0; i<n; ++i) printf("%lld ", res_min[i]); puts(""); } } return 0; }
相关文章推荐
- ZOJ 3798 Abs Problem
- ZOJ 3798 Abs Problem(规律题)
- zoj 3905(dp+滚动数组)
- [ZOJ 3682] E - Cup 3 (背包DP计数 + 滚动数组)
- ZOJ 3798 Abs Problem
- ZOJ 3798 Abs Problem
- 【cqbzoj1510】 遇见 滚动数组 dp 解题报告
- ZOJ 3798 Abs Problem(找规律)
- 组队赛#1 解题总结 ZOJ 3798 Abs Problem (找规律+打表)
- zoj 3798 Abs Problem( ZOJ Monthly, August 2014 - A)
- zoj3798 Abs Problem 水题
- ZOJ-3798-Abs Problem
- sgu 108 self number(数学问题滚动数组)
- Poj 1159-Palindrome DP (滚动数组优化)
- Codeforces 837D Round Subset【思维+Dp+滚动数组】
- HDU 1024 Max Sum Plus Plus【DP+滚动数组】
- ZOJ 2112 Dynamic Rankings(树状数组套主席树)
- 滚动数组
- POJ 2363 Blocks (ZOJ 1910) 数学
- ZOJ - 3203 Light Bulb (数学公式,或者,三分)