校赛题目

A best fit ring 线段树+DP

给一些点的坐标和点的值,同环的分数要加和,然后询问时要求给出最大值的范围,也就是连续环值最大(最大连续子段和),询问的过程中会有点的值的更改。

code:

#include <cstdio>
#include <iostream>
#include <algorithm>
typedef struct{
    int dis;
    int v;
    int id;
}Node;
Node p[100001]; //存储节点,然后聚合同环节点 
int v[100001];  //存储每个节点值,方面,后面更改 
int id[100001]; //存储该节点的环值,也就是线段树的叶子编号。 
bool cmp(const Node &a, const Node &b)
{
    if ( a.dis <= b.dis )
        return true;
    return false;    
}

typedef struct{
    int lmax, rmax, max, sum;
    int l, r, mid;
}TNode;

TNode tree[400010];
int max(int a, int b)
{
    return (a > b ? a : b);
}
void merge(int i)
{
    int l = i << 1, r = l + 1;
    
    tree[i].sum = tree[l].sum + tree[r].sum;
    
    tree[i].lmax = max(tree[l].lmax, tree[r].lmax + tree[l].sum);
        
    tree[i].rmax = max(tree[r].rmax, tree[l].rmax +tree[r].sum);
    
    tree[i].max = tree[l].rmax + tree[r].lmax;  //最大值出现的三种可能, 左半部分最大值,右半部分最大值,中间最大值 
    if ( tree[i].max < tree[l].max )
        tree[i].max = tree[l].max;
    if ( tree[i].max < tree[r].max )
        tree[i].max = tree[r].max;    
}
void build(int l, int r, int ind)
{
    int mid;
    tree[ind].l = l;
    tree[ind].r = r;
    if ( l == r )
    { 
        tree[ind].max = tree[ind].lmax = tree[ind].rmax = tree[ind].sum = p[l].v;
        return ;    
    }    
    if ( l < r ) //可以不判断 
    {
        mid = tree[ind].mid = (l + r ) >> 1;
        build(l, mid, ind << 1);
        build(mid+1, r, (ind << 1) + 1);
        merge(ind); //合并左右子集 
    }   
} 

void insert(int l, int r, int ind, int val)
{
    if ( l == tree[ind].l && tree[ind].r == r )
    {
        tree[ind].max = tree[ind].lmax = tree[ind].rmax = tree[ind].sum = p[l].v;
        return ;    
    }        
    int mid = tree[ind].mid;
    if ( l > mid )
    {
        insert(l, r, (ind << 1 ) + 1, val);
    }
    else if ( r <= mid )  //可以不判断,直接 insert(l, r, ind << 1, val); 
    {
        insert(l, r, ind << 1, val); 
    }
    else
    {
        insert(l, r, ind << 1, val);
        insert(l, r, (ind << 1 ) + 1, val); 
    }   
   
    merge(ind);  
}

int main()
{
    int n;
    int x, y;
    int i;
    int tot;
    int m;
    char str[10];
    while ( scanf("%d", &n ) != EOF )
    {
        for ( i = 1; i <= n; ++i )
        {
            scanf("%d%d%d",&x, &y, &p[i].v);
            p[i].dis = x * x + y * y;
            p[i].id = i;
            v[i] = p[i].v;
        } 
       std::sort(p+1, p+1+n, cmp);

        id[p[1].id] = 1;
        tot = 1;
        
        for ( i = 2; i <= n; ++i )
        {
            if ( p[i].dis == p[i-1].dis)
            {
                p[tot].v += p[i].v;    
            }    
            else
            {
                p[++tot].v = p[i].v;
            }
            id[p[i].id] = tot;
        }
        build(1, tot, 1);
        
        scanf("%d", &m);
        while (m--)
        {
            scanf("%s", str);
          
            if ( str[0] == 'Q')
            {
                printf("%d\n", tree[1].max);    
            }
            else
            {
                scanf("%d%d", &x, &y);
                p[id[x]].v = p[id[x]].v - v[x] + y;
                v[x] = y;
                insert(id[x], id[x], 1, y);
            }    
        }
    } 
         
    return 0;    
} 
 

Shortest Path

DP: 青蛙过河的变种,时间要求很严,1sec。开始在1石头上,要求到n石头上,输出最小步数,不能到达输出-1。

      每个石头上有个值r,代表从该石头可以向前最多到达的距离。

      按照连续范围遍历的思想,时间复杂度为O(n)。

 

#include <cstdio>

int dp[100001];
int a[100001];
int max(int x, int y)
{
    if ( x > y )    return x;
    return y;
}
int main()
{
    int tc;
    int n;
    int i, left ,right, maxright;
    int ans;
    scanf("%d", &tc);
    {
        while(tc--)
        {
            scanf("%d", &n);
            for ( i = 0; i < n; ++i )
                scanf("%d", &a[i]);
            left = 0;
            right = 1;
            for ( ans = 0; ; ++ans)
            {
                if ( left >= right )
                {
                    ans = -1;
                    break;
                }
                if ( left >= n - 1 || n - 1 < right)
                    break;
                maxright = -1;
                for ( i = left; i < right ; ++i )
                    maxright = max(maxright, a[i] + i + 1);
                left = right;
                right = maxright;
            }
            
            printf("%d\n", ans);
        }
    }
    return 0;
}
     
 

 

play beans

搜索模拟:开始题读错了,认为,要自己枚举产生的空格顺序。题目中已经限定了枚举顺序,从上到下,从左到右。

我在想要是按我的理解的那样,该怎么做这道题???

#include <cstdio>
#include <cstring>

int count(int h, int w, char g[][21])
{
    int cnt = 0;
    int i , j;
    for ( i = 0; i < h; ++i )
        for ( j = 0; j < w; ++j )
            if ( g[i][j] != '.' )
                cnt++;
    return cnt;    
}

void dis(int h, int w, char g[][21], int i, int j )
{
    int fang[4][2] = {{0,1},{0,-1}, {1,0},{-1,0}};
    int ii, x, y, c;
    int tag[27];
    int que[27][2];
    for ( ii = 0; ii < 27; ++ii)
        tag[ii] = 0;
    for ( ii = 0; ii < 4; ii++)
    {
        x = i + fang[ii][0];
        y = j + fang[ii][1];
        while ( x >= 0 && x < h && y >=0 && y < w )
        {
            if ( g[x][y] != '.' )
            {
                c = g[x][y] -'A';
                if ( tag[c] )
                {
                    g[x][y] = '.';
                    g[que[c][0]][que[c][1]] = '.';
                }
                else
                {
                    tag[c] = 1;
                    que[c][0] = x;
                    que[c][1] = y;    
                }   
                break; 
            } 
            x += fang[ii][0];
            y += fang[ii][1];
        }
    }       
}
void solve(int h, int w, char g[][21])
{
    int cnt = count(h,w,g);
    char gg[21][21];
    int i , j;

    for ( i = 0; i < h; ++i )
        strcpy(gg[i],g[i]);
    for ( i = 0; i < h; ++i )
    for ( j = 0; j < w; ++j )
        if ( g[i][j] == '.' )
            dis(h, w, gg, i, j);  
    for ( i = 0; i < h; ++i )
        strcpy(g[i],gg[i]);
    if ( cnt == count(h,w,g) )
        return ;
    solve(h,w,g);
}


int main()
{
    char g[21][21];
    int n;
    int i;
    int h, w;
    while (scanf("%d%d", &h, &w) != EOF && h + w)
    {
        for ( i = 0; i < h; ++i )
            scanf("%s", g[i]);
        solve(h,w,g);
        printf("%d\n",count(h,w,g));
    }
        
    return 0;
}
 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值