hdu 5808 分治求解

4 篇文章 0 订阅

Price List Strike Back

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 262144/131072 K (Java/Others)
Total Submission(s): 517    Accepted Submission(s): 175


 

Problem Description

There are n shops numbered with successive integers from 1 to n in Byteland. Every shop sells only one kind of goods, and the price of the i-th shop's goods is vi. The distance between the i-th shop and Byteasar's home is di.

Every day, Byteasar will purchase some goods. On the i-th day, he will choose an interval [li,ri] and an upper limit ci. Then, he will visit each shop with distance at most ci away from home in [li,ri], buy at most one piece of goods from each shop and go back home. Of course, he can also choose to buy nothing. Back home, Byteasar will calculate the total amount of money he has costed that day and write it down on his account book, denoted as sumi.

However, due to Byteasar's poor math, he may calculate it wrong. 

Please write a program to help Byteasar judge whether each number is sure to be calculated wrong.

 

 

Input

The first line of the input contains an integer T (1≤T≤10), denoting the number of test cases.

In each test case, the first line of the input contains two integers n,m (1≤n≤20000,1≤m≤100000), denoting the number of shops and the number of records on Byteasar's account book.

The second line of the input contains n integers v1,v2,...,vn (1≤vi≤100), denoting the price of the i-th shop's goods.

The third line of the input contains n integers d1,d2,...,dn (1≤di≤109), denoting the distance between the i-th shop and Byteasar's home.

Each of the next m lines contains four integers li,ri,ci,sumi (1≤li≤ri≤n,1≤ci≤109,1≤sumi≤100), denoting a record on Byteasar's account book.

 

 

Output

For each test case, print a line with m characters. If the i-th number is sure to be calculated wrong, then the i-th character should be '1'. Otherwise, it should be '0'.

 

 

Sample Input

 

2 3 3 3 3 3 2 4 3 3 3 5 3 3 3 3 1 2 3 1 3 5 4 5 1 2 4 2 1 8 9 2 1 1 5 1 3 4 4 1 5 1 5 3 5 1 3 5 1

 

 

Sample Output

 

011 1101

 

 

Source

BestCoder Round #86

 

 

Recommend

wange2014   |   We have carefully selected several similar problems for you:  6385 6384 6383 6382 6380 

题意: 现在有n家商店在一条马路上,分别编号1到n 然后小明出去了m 趟,每次出去小明总会选择在l到r 编号之间的商店买东西,并且要求商店距离小明家的距离小于等于c ,然后小明回家后将花的钱记下来,那么你要确定是小明是否记错了,记错输出1,没有输出0 。商店只有一个价钱为val的商品。

思路: 分治求解,定义dp1[i][j] 表示从i到mid 之间花费j元的最小距离, dp2[ i ][ j ] 表示从mid+1到 i 之间花费j 元的最小花费,那么对于询问 L,R,C,SUM 如果dp1[ L ][ j ]  和 dp2[ R ][ SUM -j ] 的最大值不超过c 那么就肯定是合理的。 

然后分治去考虑区间l,r;

代码: 

#include<bits/stdc++.h>

using namespace std;
const int inf =0x3f3f3f3f;
const int N =2e+5;
const int M =1e5+5;

struct node
{
    int l,r,c,sum;
    int index;
}q[M],tmp[M],tmp2[M];

int val[N];
int dis[N];
int n,m;
int dp1[N][105];
int dp2[N][105];
bool ans[M];
//bitset<M> ans;

template <class T>
inline void scan_d(T &ret)
{
    char c;
    ret = 0;
    while ((c = getchar()) < '0' || c > '9');
    while (c >= '0' && c <= '9')
    {
        ret = ret * 10 + (c - '0'), c = getchar();
    }
}

template <class T>
void print_d(T x)
{
    if (x > 9)
    {
        print_d(x / 10);
    }
    putchar(x % 10 + '0');
}

void getdp1(int l,int r)
{
    for(int i=1;i<=100;i++) dp1[r][i]=inf;
    dp1[r][0]=0;   dp1[r][val[r]]=dis[r];
    for(int i=r-1;i>=l;i--){
        for(int j=100;j>=0;j--){
            if(j>=val[i]){
                dp1[i][j]=min(dp1[i+1][j],max(dp1[i+1][j-val[i]],dis[i]));
            }
            else dp1[i][j]=dp1[i+1][j];
        }
    }
}

void getdp2(int l,int r)
{
    for(int i=1;i<=100;i++) dp2[l][i]=inf;
    dp2[l][0]=0; dp2[l][val[l]]=dis[l];
    for(int i=l+1;i<=r;i++){
        for(int j=100;j>=0;j--){
            if(j>=val[i]){
                dp2[i][j]=min(dp2[i-1][j],max(dp2[i-1][j-val[i]],dis[i]));
            }
            else dp2[i][j]=dp2[i-1][j];
        }
    }
}

void solve(int l,int r,int ql,int qr)
{
    if(ql>qr) return ;
    if(l==r){
        for(int i=ql;i<=qr;i++){
            if(val[r]==q[i].sum&&dis[r]<=q[i].c) ans[q[i].index]=1;
        }
        return ;
    }

    int p1,p2,p3;
    p1=ql; p2=qr; p3=0;
    int mid=(l+r)>>1;
    for(int i=ql;i<=qr;i++){
        if(q[i].r<=mid) q[p1++]=q[i];
        else if(q[i].l>mid) tmp[p2--]=q[i];
        else tmp2[p3++]=q[i];
    }

    if(p3){ /// 表示有LR 在 mid 的两边的情况, 那么处理出来,然后再分治.
        getdp1(l,mid);
        getdp2(mid+1,r);

        for(int i=0;i<p3;i++){
            int L=tmp2[i].l; int R=tmp2[i].r; int sum=tmp2[i].sum;
            for(int j=0;j<=sum;j++){
                if(max(dp1[L][j],dp2[R][sum-j])<=tmp2[i].c) ans[tmp2[i].index]=1;
            }
        }
    }

    for(int i=p2+1;i<=qr;i++){
        q[i]=tmp[i];
    }
    solve(1,mid,ql,p1-1);
    solve(mid+1,r,p2+1,qr);
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d %d",&n,&m);
        for(int i=1;i<=n;i++) scanf("%d",&val[i]);//scan_d(val[i]);
        for(int i=1;i<=n;i++) scanf("%d",&dis[i]);//scan_d(dis[i]);
        for(int i=1;i<=m;i++){
            scanf("%d %d %d %d",&q[i].l,&q[i].r,&q[i].c,&q[i].sum);
            //scan_d(q[i].l); scan_d(q[i].r); scan_d(q[i].c); scan_d(q[i].sum);
            q[i].index=i;
        }
        for(int i=0;i<=m;i++) ans[i]=false;
        solve(1,n,1,m);
        for(int i=1;i<=m;i++) printf("%d",ans[i]^1);
        puts("");
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值