Icpc从零开始的学习之旅(更新至2023/04/24)

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,争取变绿哈哈。

  • 9
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值