逼近法(例 poj3208、poj1037)
逼近法是一种很奇妙的算法,以为“逼近”这一种思想在很多的算法中都有体现。诸如:像我们的二分答案,不断地排除决策集合的一半以接近我们的最终答案;我们的树上倍增求 $ LCA $ 算法,一次次的减小我们跳的距离以确定祖先的准确位置;我们的模拟退火需要用一个温度,每次操作后这个温度一定会下降,逼近正确答案;再如我们大多数函数的收敛性,在多次计算后会趋向某一定值;还有我们DP的拼凑与试填的思想也有逼近的味道。
我们逼近的前提就在于我们是否可以在每一次操作后排除一些决策集合,并且是高效的排除。就像:银河系 -> 太阳系 -> 太阳系 -> 地球 -> 中国 -> 湖南 -> 长沙。还有我做出来的第一道逼近题:存在很多长度为 $ n $ 的有26个字母组成的字符串,我们将他们按字典序排序,现在给出序号或字符串,要求输出它对应的序号或字符串。这是一道傻逼题,我们可以试填第一个字母,然后它后面剩余的位置有很多种填法,我们看这么多填法是否大于我们的序号,然后我们从小到大填,这样可以确定第一个字母,紧接着可以推出第二个第三个.....然后就是答案。
虽然写的都是些浅显的东西,但如果这个思想和其他东西串联起来就不见得简单了。好了说白了就是来写题解的,不管这么多了。。。。。。。。。。。。。。。。。。。。
Poj 1037 A decorative fence
大致题意:我们要构建长度为 $ N $ 的排列,使得排列里的每一个元素同时大于或小于旁边两个数。可以预见这样的数很多,我们将这些排列按字典序排序,现在给出序号求对应的排列。
$ solution: $
就是我举的那个例子的一个变形,只不过多了一个限制:(每一个元素同时大于或小于旁边两个数)。这样我们只需要在逼近的时候特判第一个数是大于或小于第二个数(当然不能忘记我们DP第一维始终得是排列长度,这样才符合逼近思想),然后在逼近的同时维护大于和小于即可!
$ code: $
#include<iostream>
#include<cstdio>
#include<iomanip>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<ctime>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#define ll long long
#define db double
#define inf 0x7fffffff
#define rg register int
using namespace std;
ll m;
int t,n,l;
ll f[25][25][2];
bool use[25];
inline ll qr(){
register char ch; register bool sign=0; ll res=0;
while(!isdigit(ch=getchar())) if(ch=='-')sign=1;
while(isdigit(ch)) res=res*10+(ch^48),ch=getchar();
return sign?-res:res;
}
int main(){
//freopen(".in","r",stdin);
//freopen(".out","w",stdout);
n=20; f[1][1][0]=f[1][1][1]=1;
for(rg i=2;i<=n;++i){
for(rg j=1;j<=i;++j){
for(rg k=1;k<j;++k)
f[i][j][1]+=f[i-1][k][0];
for(rg k=j;k<i;++k)
f[i][j][0]+=f[i-1][k][1];
}
} t=qr();
while(t--){
n=qr(); m=qr();
register bool k=0;
for(rg i=1;i<=n;++i) use[i]=0;
for(rg i=1;i<=n;++i){
if(f[n][i][1]>=m){
k=1; l=i; break;
} else m-=f[n][i][1];
if(f[n][i][0]>=m){
k=0; l=i; break;
} else m-=f[n][i][0];
}use[l]=1; printf("%d",l);
for(rg i=n-1;i>=1;--i){
k^=1; rg s=0;
for(rg j=1;j<=n;++j){
if(use[j])continue;; ++s;
if((!k&&j<l)||(k&&j>l)){
if(f[i][s][k]>=m){
l=j; break;
} else m-=f[i][s][k];
}
}printf(" %d",l); use[l]=1;
}puts("");
}
return 0;
}
Poj 3208 Apocalypse Someday
大致题意:我们规定所有含有连续三个数字6的自然数都是“神秘数”。我们将这些数按字典序排序(及时从小到大),现在给出序号,让你求出对应的“神秘数”。
$ solution: $
又是一道变形题,但这一次改的比较难了一点,因为它需要连续的三个六,这给我们的逼近带来了后效性,如果我们确定的上一个数是6,那么这次逼近里面,开头只带有两个数字6的数也会加如决策集合。所以我们DP维护数字长度为i,含有连续的j个六的数字有多少。然后在逼近时另取一个变量来存已经连续确定了几个六然后找准决策集合进行逼近!
$ code: $
#include<iostream>
#include<cstdio>
#include<iomanip>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<ctime>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#define ll long long
#define db double
#define inf 0x7fffffff
#define rg register int
using namespace std;
int t,n,m;
ll f[25][4];
inline int qr(){
register char ch; register bool sign=0; rg res=0;
while(!isdigit(ch=getchar())) if(ch=='-')sign=1;
while(isdigit(ch)) res=res*10+(ch^48),ch=getchar();
return sign?-res:res;
}
int main(){
//freopen(".in","r",stdin);
//freopen(".out","w",stdout);
f[0][0]=1;
for(rg i=0;i<20;++i){
for(rg j=0;j<3;++j){
f[i+1][j+1]+=f[i][j];
f[i+1][0]+=f[i][j]*9;
}f[i+1][3]+=f[i][3]*10;
} t=qr();
while(t--){
n=qr(); rg k=3;
for(m=3;f[m][3]<n;++m);
for(rg i=m;i>=1;--i){
for(rg j=0;j<=9;++j){
ll tot=f[i-1][3];
if(j==6||!k)
for(rg o=max(k-(j==6),0);o<3;++o)
tot+=f[i-1][o];
if(tot<n)n-=tot;
else{
if(k)j==6?--k:k=3;
printf("%d",j);
break;
}
}
}puts("");
}
return 0;
}
逼近法(例 poj3208、poj1037)的更多相关文章
- Leetcode 11. Container With Most Water(逼近法)
11. Container With Most Water Medium Given n non-negative integers a1, a2, ..., an , where each repr ...
- 最新IP地址数据库 二分逼近&二分查找 高效解析800万大数据之区域分布
最新IP地址数据库 来自 qqzeng.com 利用二分逼近法(bisection method) ,每秒300多万, 比较高效! 原来的顺序查找算法 效率比较低 readonly string i ...
- POJ 3889 Fractal Streets(逼近模拟)
$ POJ~3889~Fractal~Streets $(模拟) $ solution: $ 这是一道淳朴的模拟题,最近发现这种题目总是可以用逼近法,就再来练练手吧. 首先对于每个编号我们可以用逼近法 ...
- openjudge-膨胀的木棍
http://noi.openjudge.cn/ch0111/09/ 总时间限制: 1000ms 内存限制: 65536kB 描述 当长度为L的一根细木棍的温度升高n度,它会膨胀到新的长度L'=(1 ...
- 分类器的评价指标-ROC&AUC
ROC 曲线:接收者操作特征曲线(receiver operating characteristic curve),是反映敏感性和特异性连续变量的综合指标,roc 曲线上每个点反映着对同一信号刺激的感 ...
- POJ 1905 Expanding Rods 木棍膨胀
描述 当长度为L的一根细木棍的温度升高n度,它会膨胀到新的长度L'=(1+n*C)*L,其中C是热膨胀系数. 当一根细木棍被嵌在两堵墙之间被加热,它将膨胀形成弓形的弧,而这个弓形的弦恰好是未加热前木棍 ...
- P2750 贰五语言Two Five USACO5.5 记忆化搜索
正解:记搜+逼近 解题报告: 神仙题预警,,, 我真滴觉得还是挺难的了,,, 大概说下思路趴QAQ 首先我们要知道逼近法是什么! 逼近法,有点像二分的思路,以这题为例举个eg 假如它给了个数字k.我们 ...
- NOI2001 方程的解数
1735 方程的解数 http://codevs.cn/problem/1735/ 2001年NOI全国竞赛 时间限制: 5 s 空间限制: 64000 KB 题目描述 Descripti ...
- 转载论文关于fir滤波器的fpga实现
摘 要 本文讨论的FIR滤波器因其具有严格的线性相位特性而得到广泛的应用.在工程实践中,往往要求信号处理具有实时性和灵活性,本论文研究FIR的FPGA解决方案正体现了电子系统的微型化和单片化. 本论文 ...
随机推荐
- python 写excal
workbook.save(filename)
- VS链接错误: LNIK1123
问题:编译一个VS工程程序,出现连接错误:"LNK1123: 转换到 COFF 期间失败: 文件无效或损坏" 原因分析:连接器LNK是通过调用cvtres.exe完成文件向coff ...
- VBA Split()函数
Split()函数返回一个数组,其中包含基于分隔符分割的特定数量的值. 语法 Split(expression[,delimiter[,count[,compare]]]) 参数说明 Expressi ...
- “a++” 与 “++a” 的区别
很久不写 C++ 程序,今天测试一段代码的过程中,发现自己连最基础的 C++ 知识都忘了,汗!!! a++ 与 ++a 都是表达式,他们都有值.其中: 1)a++ 的值是 a 的原始值,这个表达式的功 ...
- mode(BZOJ 2456)
Description 给你一个n个数的数列,其中某个数出现了超过n div 2次即众数,请你找出那个数. Input 第1行一个正整数n.第2行n个正整数用空格隔开. Output 一行一个正整数表 ...
- 洛谷 [T21778] 过年
离线扫描线+查分+线段树 我们发现,这个题的询问都是离线的,所以我们尝试用离线扫描线的方法来处理 对于每一次操作,我们维护一个差分数组, 在询问的时候,我们用一根扫描线,从左往右扫,并用线段树维护,每 ...
- 自己写了一个超级简便且傻瓜式的且功能强大的CSV组件(并且代码优雅,绝对没有一行多余的代码)
github地址: https://github.com/yangfeixxx/chipsCSV.git 解决的问题:解决了传统的CSV工具类对于实体类无法自动化封装为带表头的CSV文件的痛点,在读取 ...
- 对Netflix Ribbon的Loadbalancer类源码设计合理性的一点质疑
首先,这只是我个人的一点质疑,可能是因为我自己菜没有领悟到作者的意思,也正因此,想发出来跟大家一起探讨. 在昨晚,我因为在编写自己的开源项目的负载均衡模块(这是我开源项目的介绍:https://www ...
- Neo4j 第七篇:模式(Pattern)
模式和模式匹配是Cypher的核心,使用模式来描述所需数据的形状,该模式使用属性图的结构来描述,通常使用小括号()表示节点,-->表示关系,-[]->表示关系和关系的类型,箭头表示关系的方 ...
- SPOJ 26108 TRENDGCD - Trending GCD
Discription Problem statement is simple. Given A and B you need to calculate S(A,B) . Here, f(n)=n, ...