这周想写一个关于二分的专题...
忙活忙活下把~.
2018-11-13 :
今天做着做这dp题发现其实自己前面的很多知识都没有进行整合,还有有一些部分知识完全忘记了...只保留了某些操作的记忆。直接导致PJ组第三题花了接近六小时时间.其实这个时间是非常不合理的。从一开始就想明白过程,但是却一直想着别人怎么实现,别人怎么想。事实上别人的那篇博客的思路描述是有错误的.直接浪费了两个小时去想一个错误的东西(事后跟博主反馈了,博主那笔也确认这个错误...唯一欣慰的了)
我需要去阅读书籍和学习新的知识点.但千万别忘记了以前会的。
这周订了个小目标就是把洛谷试炼场上的线性dp刷完。当然二分专题还是要弄的。
在刷线性dp前,做了一组简单线性数据结构的专题练习(很自信的去做最后两道题):
#include <iostream>
#include <stack>
#include <sstream>
using namespace std;
int main(){
stack<int> q;
string s = "";
int d = 0;
getline(cin,s);
int len = s.length();
for(int i = 0 ; i < len ; i++){
if( '0' <= s[i] && s[i] <= '9') d = (d*10 + s[i]-'0');
else if(s[i] == '.') q.push(d) ,d = 0 ;
else if(s[i] == '@') cout << q.top();
else{
int num2 = q.top();
q.pop();
int num1 = q.top();
q.pop();
if(s[i] == '+') q.push(num1+num2);
if(s[i] == '-') q.push(num1-num2);
if(s[i] == '*') q.push(num1*num2);
if(s[i] == '/') q.push(num1/num2);
}
}
}
233都不想吐槽自己....在输入字符串中把数字提取出来.可以利用d = (d*10 + s[i]-'0'); 一个个提取出来...
数字转换字符串也可以阿 s = char(d%10 + '0') + s;
@@@@@一开始考虑sscanf() 和sprintf()。。实际上没太认真看... !!!!!!!!!!!!!(明天翻阅下吧!)
实际上呢..我在查阅资料的时候发现了一个神奇的表达式 if(*((char*)&data) == 0x1)
int big_little_endian(){
int data = 0x1;
if( *((char*)&data) == 0x1)
return LITTLE_ENDIAN; // 前面定义的LITTLE_ENDIAN = 0
return BIG_ENDIAN; // 前面定义的BIG_ENDIAN = 0
}
计组讲过的...AMD和英特尔的CPU对数据处理的方式不一样..(有待继续研究)
对应数据的高字节存放在低地址就是大尾,反之,高字节存放在高地址的就是小尾。
比如 short int a = 0x1234
大尾存放时:
偏移地址 存放内容
0x0000 0x12
0x0001 0x34
小尾存放:
偏移地址 存放内容
0x0000 0x34
0x0001 0x12
- int data = 0x1 (一个int占四个字节)
- 大尾存放时:
- 偏移地址 存放内容
- 0x0000 0x00
- 0x0001 0x00
- 0x0002 0x00
- 0x0003 0x01
- 小尾存放:
- 偏移地址 存放内容
- 0x0000 0x01
- 0x0001 0x00
- 0x0002 0x00
- 0x0003 0x00
https://bbs.youkuaiyun.com/topics/220075662 有比较详细的去解释(char*)&data)
有一个回答很是经典
------------------------
取data的地址
得到的是一个指针
然后转换成一个char指针
也就是说把原来data存放的数据按照char去解释!
不同的指针类型就是不同的解释方法!
配合代码理解:
#include <cstdio>
#include <iostream>
using std::cout;
int main()
{
int data = 65;
int *d;
d = &data;
char *p;
//p = &data;//这句编译不通过
p = (char*)&data;//如1楼所说的
printf("%d %d %d", &data, d, p);
printf("\n%d %c\n", *d, *p);
cout << *d << " " << p << "\n";//上下两句输出相同
return 0;
}
队列安排
#include <iostream>
#include <cstdio>
using namespace std;
const int mmax = 1e5+5;
int st[mmax][2]; //st[i][0] 代表与i左相邻的结点编号, st[i][1] 代表与i右相邻的结点编号
int main(){
int n,id,dir,m,d;
scanf("%d",&n);
st[0][1] = 1,st[0][0] = -1;
st[1][0] = 0,st[1][1] = -1; //-1代表结束
for(int i = 2; i <= n ;i++){
scanf("%d%d",&id,&dir);
int lin = st[id][dir]; //某一个方向的相邻编号
if(lin == -1){ //
st[id][dir] = i ;
st[i][!dir] = id; //
st[i][dir] = -1;
}
else{
st[i][dir] = lin,st[i][!dir] = id;
st[lin][!dir] = i,st[id][dir] = i;
}
}
scanf("%d",&m);
while(m--){
scanf("%d",&d);
if(st[d][0] == -1 && st[d][1] == -1) continue;
int l = st[d][0] ,r = st[d][1];
st[l][1] = r; //d左边的结点指向 d右边的结点
if(r == -1) continue;
st[r][0] = l;
st[d][0] = -1,st[d][1] = -1;
}
int fir = 0;
while(st[fir][1] != -1){
cout << st[fir][1] << " ";
fir = st[fir][1];
}
}
纯数组模拟了链式的写法。虽然不能释放空间...
这道题最不能忍的就是...我居然忘记了st[fir][0] 和st[fir][1] 是代表fir的两个相邻结点.我以为....跟指针一样 fir++就能得到下一个相邻的结点.....
然而PS---->看到了一个树去模拟的思路:
#include<cstdio>
struct lol{int lc,rc,v;} d[101000];//v表示是否被删,lc是左儿子(相当于当前点的前面的第一个数),rc是右儿子 (相当于当前点的后面的第一个数)
void dfs(int x)//用中序遍历的方法输出
{
if(x==-1)return;//-1代表没空,如果该点为空就不需要再往下找
dfs(d[x].lc);//搜左儿子
if(d[x].v==0)printf("%d ",x);//搜完左儿子(相当于输完前面的人的编号)输出自己的编号
dfs(d[x].rc);//搜右儿子
}
int main()
{
int n,m;scanf("%d",&n);
d[1].v=0;d[1].lc=d[1].rc=-1;
//-1表示空,初始化第一个点
for(int i=2;i<=n;i++)
{
int x,y;scanf("%d %d",&x,&y);
d[i].lc=d[i].rc=-1;d[i].v=0;//先初始化i点
if(y==0)
{
if(d[x].lc!=0)//当d[x]有左儿子,把当前点的左儿子设为d[x]的左儿子,d[x]左儿子设为当前点
{d[i].lc=d[x].lc;d[x].lc=i;}
//否则,把d[x]有左儿子设为当前点
else d[x].lc=i;
}
else
{
if(d[x].rc!=0)//当d[x]有右儿子,把当前点的右儿子设为d[x]的右儿子,d[x]右儿子设为当前点
{d[i].rc=d[x].rc;d[x].rc=i;}
//否则,把d[x]有右儿子设为当前点
else d[x].rc=i;
}
}
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
int x;scanf("%d",&x);d[x].v=1;//删除x点
}
dfs(1);//利用中序遍历输出
}
删除操作:对于每个结点用了一个标记符此元素是否被删除.这种树形结构的删除操作也是非常方便的。
添加元素操作:对于每个结点t它只可能作为根结点rt右儿子或者左儿子.若rt对应的儿子不存在.直接插入即可.
容易犯错的地方... 就是对于每一个新添加的结点必须进行初始化操作.
中序遍历的优势大大体现出来。。。
@@@@@突然给了我一个启发?为什么链式结构的不可以用一个标记符来确定此元素是否被删除?还可以实现快速删除,快速回复.软删除的功能就体现出来了
#include <iostream>
#include <stack>
using namespace std;
int main(){
char c;
bool s = true; //ÓÐЧ
stack<char> op;
while(cin >> c){
if(c == '@') break;
else if( c == '(' ) op.push(c);
else if( c == ')' ){
if(op.size() > 0) op.pop();
else s = false;
}
}
if( op.size() > 0) s = false;
if(s)
cout << "YES" << endl;
else
cout << "NO" << endl;
}
括号匹配的核心在于每一个'('的一定要匹配唯一')'的.怎么去实现呢?可以用栈.亦可以用变量去统计当前'('的数量.但是有可能在中途整个表达式就不符合条件了
所以说阿.年轻人还是思路梳理清楚了.一步步写.
PS明天要出题~