BestCoder Round #50 (div.2) hdu5366、5367(dp+动态线段树)

The mook jong

问题描述

ZJiaQ为了强身健体,决定通过木人桩练习武术。ZJiaQ希望把木人桩摆在自家的那个由1*1的地砖铺成的1*n的院子里。由于ZJiaQ是个强迫症,所以他要把一个木人桩正好摆在一个地砖上,由于木人桩手比较长,所以两个木人桩之间地砖必须大于等于两个,现在ZJiaQ想知道在至少摆放一个木人桩的情况下,有多少种摆法。

输入描述

输入有多组数据,每组数据第一行为一个整数n(1 < = n < = 60)

输出描述

对于每组数据输出一行表示摆放方案数

输入样例

1
2
3
4
5
6

输出样例

1
2
3
5
8
12

思路:dp[i][0]表示第i个格子不放的情况,dp[i][1]表示第i个格子放的情况

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<algorithm>
using namespace std;
typedef long long LL;
const int maxn=100010;
const int maxm=1010;
const int MOD=1e9+7;
const int INF=0x3f3f3f3f;
LL dp[maxn][2];
int N;
int main()
{
    while(scanf("%d",&N)!=EOF)
    {
        memset(dp,0,sizeof(dp));
        dp[0][0]=1;
        dp[1][1]=dp[2][1]=dp[3][1]=1;
        for(int i=1;i<=N;i++)
        {
            dp[i][0]=dp[i-1][0]+dp[i-1][1];
            if(i>3)dp[i][1]=dp[i-3][0]+dp[i-3][1];
        }
        printf("%I64d\n",dp[N][0]+dp[N][1]-1);
    }
    return 0;
}

digger

问题描述

地主小花有n座山,这些山在地主家门前排成一条直线。这些山一开始均有相同的高度。 每一天,小花都会要求ZJiaQ开挖机把几座山挖掉一定高度,或者给一些山堆上一些高度。并且要求报告ZJiaQ报告现在有多少座山属于“高山脉”
当一排山的高度相等,并且比这排山左边和右边的山要高时,这排山被称为高山脉。
当然,最左边和最右边的山不可能是“高山脉”的一部分

输入描述

输入有多组数据
每组数据第一行有3个整数n,q,r(1<=n<=10^9,1<=q<=50000,0<=r<=1000)
接下来的q行,每行有3个整数l,r,val(1<=l<=r<=n,-1000<=val<=1000),表示从第l座山到第r座山的高度变更了val。每次输入的l,r,val需要与前一次的答案进行异或操作得到的值才是真正的l,r,val。第一次输入的l,r,val不需要。

输出描述

输出q行,每行一个数字表示答案

输入样例

5 5 0
4 5 87
2 5 -48
3 3 17
4 5 -171
5 5 -494

输出样例

0
0
0
1
1

思路:线段树维护,因为N非常大,所以用动态线段树,具体见代码

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<algorithm>
using namespace std;
typedef long long LL;
const int maxn=50010;
const int maxm=1010;
const int MOD=1e9+7;
const int INF=0x3f3f3f3f;
int N,Q;
int root,cur;
struct Node
{
    int sum;  //共有多少高山脉
    int ch[2];//左右孩子编号
    int rsum,lsum;//从左边起、从右边起高度相同的连续的有多少个
    int lh,rh;//左边连续、右边连续的高度
    int ll,rr;//左边第一个不连续的,右边第一个不连续的高度
    int add;  
    void init(int l,int r)
    {
        add=sum=lh=rh=ll=rr=ch[0]=ch[1]=0;
        lsum=rsum=r-l+1;
    }
};
struct IntervalTree
{
    Node node[maxn*60];
    void check(int & o,int l,int r)
    {
        if(o)return;
        o=++cur;
        node[o].init(l,r);
        if(l==1)node[o].ll=INF;
        if(r==N)node[o].rr=INF;
    }
    void maintain(int o,int val)
    {
        node[o].add+=val;
        node[o].rr+=val;
        node[o].ll+=val;
        node[o].lh+=val;
        node[o].rh+=val;
    }
    void pushdown(int o,int l,int r)
    {
        if(node[o].add)
        {
            int mid=(l+r)>>1;
            check(node[o].ch[0],l,mid);
            check(node[o].ch[1],mid+1,r);
            maintain(node[o].ch[0],node[o].add);
            maintain(node[o].ch[1],node[o].add);
            node[o].add=0;
        }
    }
    void pushup(int o,int l,int r)
    {
        int mid=(l+r)>>1;
        check(node[o].ch[0],l,mid);
        check(node[o].ch[1],mid+1,r);
        int lson=node[o].ch[0],rson=node[o].ch[1];
        node[o].sum=node[lson].sum+node[rson].sum;
        node[o].lsum=node[lson].lsum;node[o].rsum=node[rson].rsum;
        node[o].lh=node[lson].lh;node[o].rh=node[rson].rh;
        node[o].ll=node[lson].ll;node[o].rr=node[rson].rr;
        if(node[lson].rh==node[rson].lh)
        {
            if(node[lson].rh>node[lson].rr&&node[rson].lh>node[rson].ll)
                node[o].sum+=node[lson].rsum+node[rson].lsum;
            if(node[lson].rsum==mid-l+1)
            {
                node[o].lsum+=node[rson].lsum;
                node[o].ll=node[rson].ll;
            }
            if(node[rson].lsum==r-mid)
            {
                node[o].rsum+=node[lson].rsum;
                node[o].rr=node[lson].rr;
            }
        }
        else
        {
            if(node[lson].lsum==mid-l+1)node[o].ll=node[rson].lh;
            if(node[lson].rh>node[rson].lh&&node[lson].rh>node[lson].rr)
                node[o].sum+=node[lson].rsum;
            if(node[rson].rsum==r-mid)node[o].rr=node[lson].rh;
            if(node[rson].lh>node[lson].rh&&node[rson].lh>node[rson].ll)
                node[o].sum+=node[rson].lsum;
        }
    }
    void update(int &o,int l,int r,int q1,int q2,int x)
    {
        check(o,l,r);
        if(q1<=l&&r<=q2)
        {
            maintain(o,x);
            return ;
        }
        pushdown(o,l,r);
        int mid=(l+r)>>1;
        if(q1<=mid)update(node[o].ch[0],l,mid,q1,q2,x);
        if(q2>mid)update(node[o].ch[1],mid+1,r,q1,q2,x);
        pushup(o,l,r);
    }
}tree;
void solve()
{
    root=cur=0;
    int ans=0;
    int l,r,val;
    for(int i=0;i<Q;i++)
    {
        scanf("%d%d%d",&l,&r,&val);
        l^=ans,r^=ans,val^=ans;
        if(l>r)swap(l,r);
        tree.update(root,1,N,l,r,val);
        ans=tree.node[1].sum;
        printf("%d\n",ans);
    }
}
int main()
{
    while(scanf("%d%d%*d",&N,&Q)!=EOF)
        solve();
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值