【HDU 5808】 Price List Strike Back (整体二分+动态规划)

Price List Strike Back
There are nn shops numbered with successive integers from 11 to nn in Byteland. Every shop sells only one kind of goods, and the price of the ii-th shop's goods is vivi. The distance between the ii-th shop and Byteasar's home is didi. 

Every day, Byteasar will purchase some goods. On the ii-th day, he will choose an interval [li,ri][li,ri] and an upper limit cici. Then, he will visit each shop with distance at most cici away from home in [li,ri][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 sumisumi. 

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.

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

In each test case, the first line of the input contains two integers n,mn,m (1n20000,1m100000)(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 nn integers v1,v2,...,vnv1,v2,...,vn (1vi100)(1≤vi≤100), denoting the price of the ii-th shop's goods. 

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

Each of the next mm lines contains four integers li,ri,ci,sumili,ri,ci,sumi (1lirin,1ci109,1sumi100)(1≤li≤ri≤n,1≤ci≤109,1≤sumi≤100), denoting a record on Byteasar's account book.
OutputFor each test case, print a line with mm characters. If the ii-th number is sure to be calculated wrong, then the ii-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


【题意】
  

  在Byteland一共有n家商店,编号依次为1到n。每家商店只会卖一种物品,其中第ii家商店的物品单价为vi ,且它到Byteasar的家的距离为di 。

  Byteasar每天都会进行一次购物,第ii天他会选择一个区间[li,ri],并给自己设定一个距离上限ci ,然后他会在编号在该区间内每家到自己家的距离不超过ci的商店购买最多一件物品,当然他也可以选择什么都不买。回家之后,Byteasar会把今天购物所花的钱的总数sumi记录在账本上。

  Byteasar的数学不好,他可能会把花的钱记错。

  请写一个程序,帮助Byteasar判断每条记录是否一定是错的。

 

【分析】

  前面是偏序问题,后面问能否拼出某个价格,且价格《=100,可以用动态规划解决。

  官方题解:

  

考虑对序列进行分治,设当前分治区间为[l,r],取mid=(l+r)/2,那么所有在[l,mid)的询问和(mid,r]的询问可以递归分治求解,故只需考虑必然经过mid的询问。

设f[i][j]表示考虑了[i,mid],目前选出的物品和为j时,所选商店到家的距离的最大值最小是多少;g[i][j]表示考虑了(mid,i],目前选出的物品和为j时,所选商店到家的距离的最大值最小是多少,f和g都能在O(100(r-l+1))的复杂度内求出。那么对于一个询问l,r,s,cl,r,s,c,只需要求出min(max(fi,gsi)),然后和c比较一下大小就好了。

时间复杂度O(100(nlogn+m)+mlogn)

  表示没有想出dis的解决方法,那个dp里面记录最小距离真是太机智。。【是我太蠢。。

  1 #include<cstdio>
  2 #include<cstdlib>
  3 #include<cstring>
  4 #include<iostream>
  5 #include<algorithm>
  6 #include<queue>
  7 using namespace std;
  8 #define Maxn 20010
  9 #define Maxm 100010
 10 #define Maxd 110
 11 #define INF 0x7fffffff
 12 
 13 int v[Maxn],d[Maxn];
 14 
 15 struct node
 16 {
 17     int l,r,c,sum;
 18 }t[Maxm];
 19 
 20 int a[Maxm],a1[Maxm],a2[Maxm];
 21 int f[Maxn][Maxd];
 22 bool ans[Maxm];
 23 
 24 int mymin(int x,int y) {return x<y?x:y;}
 25 int mymax(int x,int y) {return x>y?x:y;}
 26 
 27 void get_f(int l,int r,int mid)
 28 {
 29     for(int i=l;i<=r;i++)
 30      for(int j=0;j<=100;j++)
 31          f[i][j]=INF;
 32     for(int i=l;i<=r;i++) f[i][0]=0;
 33     int i;
 34     for(i=mid;i>=l;i--)
 35      for(int j=100;j>=0;j--)
 36      {
 37          f[i][j]=mymin(f[i][j],f[i+1][j]);
 38          if(j>=v[i]) f[i][j]=mymin(f[i][j],mymax(f[i+1][j-v[i]],d[i]));
 39      }
 40     f[mid+1][v[mid+1]]=d[mid+1];
 41     for(int i=mid+2;i<=r;i++)
 42      for(int j=100;j>=0;j--)
 43      {
 44          f[i][j]=mymin(f[i][j],f[i-1][j]);
 45         if(j>=v[i]) f[i][j]=mymin(f[i][j],mymax(f[i-1][j-v[i]],d[i]));
 46      }
 47     // for(int i=mid-1;i>=l;i--)
 48      // for(int j=0;j<=100;j++) f[i][j]=mymin(f[i][j],f[i+1][j]);
 49     // for(int i=mid+2;i<=r;i++)
 50      // for(int j=0;j<=100;j++) f[i][j]=mymin(f[i][j],f[i-1][j]);
 51 }
 52 
 53 void ffind(int l,int r,int x,int y)
 54 {
 55     if(x>y) return;
 56     if(l==r)
 57     {
 58         for(int i=x;i<=y;i++) 
 59             if(v[l]==t[a[i]].sum&&d[l]<=t[a[i]].c) ans[a[i]]=1;
 60             else ans[a[i]]=0;
 61         return;
 62     }
 63     int mid=(l+r)>>1;
 64     get_f(l,r,mid);
 65     a1[0]=a2[0]=0;
 66     for(int i=x;i<=y;i++)
 67     {
 68         if(t[a[i]].l<=mid&&t[a[i]].r>mid)
 69         {
 70             ans[a[i]]=0;
 71             for(int j=0;j<=t[a[i]].sum;j++)
 72             {
 73                 if(mymax(f[t[a[i]].l][j],f[t[a[i]].r][t[a[i]].sum-j])<=t[a[i]].c) {ans[a[i]]=1;break;}
 74             }
 75         }
 76         else if(t[a[i]].r<=mid)
 77         {
 78             a1[++a1[0]]=a[i];
 79         }
 80         else a2[++a2[0]]=a[i];
 81     }
 82     int nw=a1[0],ww=a2[0];
 83     for(int i=1;i<=a1[0];i++) a[x+i-1]=a1[i];
 84     for(int i=1;i<=a2[0];i++) a[y-i+1]=a2[i];
 85     ffind(l,mid,x,x+nw-1);
 86     ffind(mid+1,r,y-ww+1,y);
 87 }
 88 
 89 int main()
 90 {
 91     int T;
 92     scanf("%d",&T);
 93     while(T--)
 94     {
 95         int n,m;
 96         scanf("%d%d",&n,&m);
 97         for(int i=1;i<=n;i++) scanf("%d",&v[i]);
 98         for(int i=1;i<=n;i++) scanf("%d",&d[i]);
 99         for(int i=1;i<=m;i++) scanf("%d%d%d%d",&t[i].l,&t[i].r,&t[i].c,&t[i].sum);
100         for(int i=1;i<=m;i++) a[i]=i;
101         ffind(1,n,1,m);
102         for(int i=1;i<=m;i++)
103         {
104             if(ans[i]) printf("0");
105             else printf("1");
106         }
107         printf("\n");
108     }
109     return 0;
110 }
View Code

INF开小了,好惨。。

 

2017-01-16 09:15:55

 
posted @ 2017-01-16 09:07  konjak魔芋  阅读(430)  评论(0编辑  收藏  举报