UVA 11988
Broken Keyboard
数组操作链表
if (line[i] == '[') cur = 0;
else if (line[i] == ']') cur = last;
else {
next[i] = next[cur];
next[cur] = i;
if (cur == last) last = i;
cur = i;
}
我们可以用cur来模拟插入的数组位置
next[i]=next[cur]是让当前的元素的后链连上cur的尾部,next[cur]是让cur后的元素变成i,当正常插入时cur应该是链表元素的尾部所以要更新last.
UVA 210
Concurrency Simulator
学到了输入输出流
stringstream(str)可以将字符串再一次输出,此时我们可以用cmd来接收标志。
UVA 12657
Boxs in a Line
学习到了双向链表的实现和使用,还有一些细节。
void link(int L,int R,int *left,int*right){
right[L]=R;
left[R]=L;
}
UVA 122
学习到了树的建立和使用,还有内存池的建立。
void init(){
for(int i=0;i<maxn;i++){
freenodes.push_back(&node[I]);
}//初始化
struct Node{
Node*left,*right;
Node():left(NULL),right(NULL){};
}
这几天在跟着紫书学,虽然学得慢,但感觉收获颇多。
(12/20)更新
离散化算法
uva221
城市正视图
给出城市的俯视图
求取正视图中可以看见的建筑编号
由于正视图x坐标为实数
所以遍历所有x坐标不现实,故我们需要采用离散化算法来具体化每个需要遍历的坐标,我们可以发现,由于矩形在x轴上只有两个端点投影,故我们可以用坐标去重遍历,这时候我们可以判断建筑物是否在两相邻的端点中点是否可见来判断
void discreatize(int *a,int &n){
sort(a,a+n);
n=(int)(unique(a,a+n)-a);
}
离散化算法给我的感觉是很精妙,将无限化为有限,通过排序,来转移标记,将x,y,z坐标投影到排序的下标里
UVa12171
雕塑
bfs遍历立体空间
struct Cell{
int x,y,z;
Cell(int _x,int _y,int _z):x(_x),y(_y),z(_z){}
bool isvaild(){
return (0<=x&&x<nx-1&&0<=y&&y<ny-1&&0<=z&&z<nz-1);
}
Cell getNeighbor(int dir){
return Cell(x+drs[dir][0],y+drs[dir][1],z+drs[dir][2]);
}
int getv(){
return (xs[x+1]-xs[x])*(ys[y+1]-ys[y])*(zs[z+1]-zs[z]);
}
int getarea(int dir){
if(drs[dir][0]!=0)return (ys[y+1]-ys[y])*(zs[z+1]-zs[z]);
else if(drs[dir][1]!=0)return (xs[x+1]-xs[x])*(zs[z+1]-zs[z]);
else if(drs[dir][2]!=0)return (xs[x+1]-xs[x])*(ys[y+1]-ys[y]);
return -1;
}
bool iscoper(){
return sen[x][y][z]==1;
}
bool isvis(){
return sen[x][y][z]==2;
}
void setvis(){
sen[x][y][z]=2;
}
};
bfs本身不难关键是掌握设计结构体的方法
比如,设计一个可以根据方向返回相邻网格的函数。
uva 1600
patrol Pobot
学会设计节点应该怎样设计
struct node{
int x,y,d,k;
};
分层bfs这样可以将每种k的节点情况包含
比如x,y这个节点可以有很多种到达的方法
而k的储存记录了当前抵达的情况,对于1,2,3,..k
时状态相同,因为第一个到达的是距离最短的
这样记录下的是每种k下的最优这样链接下来,可以得到最优解。
uva12166
修改天平
不平衡的天平最小的修改次数
位运算
balance(l+1,id-1,deep+1);
balance(id+1,r-1,deep+1);
计算出深度与二进制下的表示来计数
对于天平的左右两边如果值不等就不平衡
对于子天平,母天平要是子天平的2的k倍
这样只要遍历节点,做一次哈希就可以解决问题
(12/28)更新
还剩三题
看了看觉得水平不够,写的话也是看题解,觉得还能学一下
先进入下一单元吧
暴力求解,学习优化
--------------------------------------分割线--------------------------------------------
(12/29)
子集生成
void subset(int n,int *A,int cur){
for(int i=0;i<cur;i++)cout<<A[i];
cout<<endl;
int s=cur?A[cur-1]+1:1;//定序
for(int i=s;i<=n;i++){
A[cur]=i;
subset(n,A,cur+1);
}
}
采用定序,每一次选取比现在最小的子集内的值
元旦诶
昨天躺平了今天补上
uva 1354
递归枚举二叉树
void dfs(int subset){
if(vis[subset])return;
vis[subset]=1;
if(((subset-1)&subset)==0)tree[subset].push_back(Tree{});//子节点空天平
else{
for(int left=subset&(subset-1);left>0;left=subset&(left-1)){
int right=subset^left;
dfs(right);dfs(left);
double dr=sum[left]/sum[subset];
double dl=sum[right]/sum[subset];
for(auto &tl:tree[left]){
for(auto &tr:tree[right]){
Tree t;
t.l=max(tl.l+dl,tr.l-dr);
t.r=max(tl.r-dl,tr.r+dr);
if(t.l+t.r<r)tree[subset].push_back(t);
}
}
}
}
}
(不会)题解的意思理解到了,先递归求取左右子树的子集再组合集合计算左右子树离根的距离
昨天没得打cf,今天也要补上,虽然上分的机会可能没了,但是也要检验自己的学习进度。
-----------------------------cf题解------------------------------------------
新年题,前面题意理解不到位,罚了三发。
C题给定一个整数数组,问是否存在一个正整数使所有数加上它后令数组中的数不互质,
思路如下:
转化判断是否对于一个质数无论加上什么数都会不存在两个数整除被p,抽屉原理,预处理数组大小的质数,遍历判断模意义下的数组是否所有余数都计数大小超过2,如果超过,无论如何都无法找到这样的数使数组两两互质。
for(int i=2;i<=100;i++){
int ok=1;
for(int j=2;j*j<=i;j++){
if(i%j==0){ok=0;break;}
}
if(ok)prime.push_back(i);
}
for(int i=0;i<prime.size();i++){
ll p=prime[i];
vector<int>cnt(p);
for(int j=0;j<n;j++){
cnt[(a[j]%p)]++;
}
if(*min_element(cnt.begin(),cnt.end())>=2){
cout<<"NO"<<endl;
return;
}
}
01/02更新
埃及分数问题
给定a,b,求若干个以一为分子的分母相加为a/b的式子
ida广度优先搜索,控制枚举的深度,这样就可以在有限的时间内枚举到想要的结果。
for(maxd=1;;maxd++){
memset(ans,-1,sizeof(ans));
if(dfs(0,get_first(a,b),a,b)){
break;
}
}
外加昨晚的c题,
给出例如如下的字符串,问能否有唯一的有效括号序列
(?)),(????)
算法也很简洁
int wh=0,cnt=0;
for(auto&c:s){
if(c=='(')cnt++;
if(c==')')int--;
if(c=='?')wh++;
if(wh+cnt==1){
wh=0;
cnt=1;
}
}
cout<<abs(cnt)==wh<<endl;
从左往右遍历字符串,如果当前的右括号比较多的时候,需要?来变成左括号,此时是唯一的可能因为如果最后一个是右扩号,那么问号可以变成任意对的有效括号,此时不唯一。
(01/04)更新
cf新年题c
最小指定前缀和
预处理前缀和,从指定的位置向两边遍历,用优先队列来储存当前访问的最大最小值,理论复杂度为m(logn);
priority_queue<ll>q;
for(int i=m-1;i>=1;i--){
q.push(a[i+1]);
if(pre[i]<sum){
sum-=2*q.top();
q.pop();
cnt++;
}
}
sum=pre[m];
priority_queue<ll,vector<ll>,greater<ll>>p;
for(int i=m+1;i<=n;i++){
p.push(a[i]);
if(pre[i]<sum){
sum+=2*p.top();
p.pop();
cnt++;
}
}
(01/10)更新
uva1602
网格动物
把格子设计为结构体,用inline函数设置成为内联函数,减少栈空间消耗,
struct Cell{
int x,y;
Cell(int _x=0,int _y=0):x(_x),y(_y){}
bool operator < (const Cell &rhs) const{
return x<rhs.x||(x==rhs.x&&y<rhs.y);
}
};
然后进行打表,把所有的情况先列出来,在计算。
cf训练题c
求n的排列对于给定的一组数组,有任意区间缺少的最小数相同,
依次求出所有数的下标,当一个数在当前的范围时可以进行排列,训练时卡在对多个数的排列组合上。
int l=p[0],r=p[0];
for(int i=1;i<=n-1;i++){
if(l<=p[i]&&p[i]<=r){
ans*=r-l+1-i;
ans%=mod;
}
else if(p[i]<l){
l=p[i];
}
else if(p[i]>r){
r=p[i];
}
}
uva690
流水线调度
位运算+回溯剪枝
具体思路就是暴力问询可能的间隔,当当前的步数加上最小的位移后仍大于或等于答案,此时剪枝。
void dfs(int *p,int d,int sum){
if(sum+dt[0]*(10-d)>=ans)return ;
if(d==10){
ans=min(ans,sum);
return;
}
for(int i=0;i<cnt;i++){
if(ok(p,dt[i])){
int p2[5];
memset(p2,0,sizeof(p2));
for(int j=0;j<5;j++){
p2[j]=(p[j]>>dt[i])|a[j];
dfs(p2,d+1,sum+dt[i]);
}
}
}
}
(01/20)更新
目前的cf水平是1300,还没能达到上青的水准,还要进一步努力,最近沉不下心来慢慢写紫书,对于优化还没有十足的把握,基本上都是朴素算法,二月开头又要准备考试了,大概十号就要自己准备考试,绩点是弄不上来了,也不想和别人争来争去,选课也是佛性选课,把自己必修的选完就ok了,正常来说水平寒假就要上蓝名但是现在也没有什么起色,十有八九可能要落后了,但是我还是打算坚持下去,今年快结尾了,我cf上也写了220道题,大概是打了70场比赛,刷题数不算多,总之要多练练。
(01/23)更新
第一次手打的快排
void mysort(vector<int>&a,int l,int r){
if(r-l>1){
int m=(r-l)/2+l;
for(int i=m-1;i>=l;i--){
if(a[i]>a[m]&&m-i>1){
swap(a[i],a[m-1]);
swap(a[m-1],a[m]);
m--;
}
else if(a[i]>a[m]){
swap(a[i],a[m]);
m--;
}
}
for(int i=m+1;i<r;i++){
if(a[i]<=a[m]&&i-m>1){
swap(a[i],a[m+1]);
swap(a[m],a[m+1]);
m++;
}
else if(a[i]<=a[m]){
swap(a[i],a[m]);
m++;
}
}
mysort(a,l,m);
mysort(a,m,r);
}
}
2023/04/24更新
经过了一段长时间的低落期,重新点亮状态,接下来继续更新,打算学习树链剖分,五一期间好好学学紫书上的动态规划,补补短板和自己的思维。走过了这么长的一段时间,我发现自己总是不能第一次就做到很好,一部分是对自己的不自信,另一方面是自己有侥幸心理,偷懒行为,自己的自律还不够,有待加强。今晚打cf,争取变绿哈哈。