[NOIP模擬][資料結構][二分]Work
阿新 • • 發佈:2019-02-17
題目描述:
題目背景: SOURCE:NOIP2015-SHY-5
假設現在離 noip 還有 m 天,有 n 個人要去參加比賽。他們每個人都有一個預定的訓練量 r[i] ,所以每一天他們都抓緊時間練習。但是由於條件限制,第 i 天只有 t[i] 的時間可以練習。
我們都知道,一個人在開始幹活以前總要浪費一些時間做一些雜七雜八的事情。現在我們假定第 i 個人每天在訓練前浪費的時間是固定的,記為 d[i] 。這段浪費掉的時間過後,選手會專心致志訓練,他們會充分利用剩下的時間。然而一個可能的情況時,一個人還在無所事事的時候,某一天的訓練時間已經過去了,所以他那一天什麼事情都沒有做。
現在請問每個人在第幾天的時候可以完成自己的訓練任務。當然會存在志向遠大但是很懶惰的人到最後也是做不完的情況。
輸入格式:
第一行兩個整數 n,m ,表示人數和天數 。
接下來一行 m 個整數 t[i] 。
接下來 n 行每行兩個整數 d[i],r[i] 。
輸出格式:
一行輸出 n 個整數表示每個人在第幾天可以完成自己的工作,如果完不成,輸出 0 。
樣例輸入:
3 3
4 2 5
1 3
2 5
3 4
樣例輸出:
1 3 0
資料範圍:
對 30% 的輸入資料 :1≤n,m≤1000
對 100% 的輸入資料 :1≤n,m≤ 200000;1≤t[i]≤1000000; 0≤d[i]≤1000000;1≤r[i]≤1000000
注意事項:
如果某人浪費的時間超過一天,不需減去負的時間。
題目分析:
對於每個人,如果你能在第i天前完成工作,那麼你必然能在第j(j>i)前完成。所以可以二分天數。於是就變成判斷是否能在第i天完成訓練。前i天的完成量等於前i天中所有比此人d大的t的總和減去天數(大於d的天數)*d。於是我們可以用樹狀陣列來維護總和與天數,如下:
1、先將訓練時間t[i]和浪費時間d[i]分別按降序排序;
2、從最大的d[1]開始,將大於此時d的t[i]加入樹狀陣列維護sum[i],i代表天數,存的是此時已加入的t的和,同時維護天數times[i],目前一共有幾天(這個天數就自然是大於d的天數)。
3、對於d[1],二分天數,詢問當前天數下i的sum和times,前i天的完成量等於sum[i]-times[i]*d[1],比較此結果與r的大小,繼續二分,直到二分出正確值。
4、其餘d以此類推,只需每次多加入一些t進入樹狀陣列。
附程式碼:
#include<iostream>
#include<cstring>
#include<string>
#include<cstdlib>
#include<cstdio>
#include<ctime>
#include<cmath>
#include<cctype>
#include<iomanip>
#include<algorithm>
using namespace std;
const int N=2e5+10;
long long sum[N];
int n,m,times[N],po=1,ans[N];
struct node{
int w;
int num;
int r;
}t[N],p[N];
int readint()
{
char ch;int i=0,f=1;
for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
if(ch=='-') {ch=getchar();f=-1;}
for(;ch>='0'&&ch<='9';ch=getchar()) i=(i<<3)+(i<<1)+ch-'0';
return i*f;
}
bool comp(const node &a,const node &b)
{
if(a.w!=b.w) return a.w>b.w;
return a.num<b.num;
}
int lowbit(int i)
{
return i&(-i);
}
void insert(int x,int w1,int w2)
{
for(int i=x;i<=m;i+=lowbit(i))
sum[i]+=w1,times[i]+=w2;
}
bool query(int x,int num)
{
long long ret=0;
for(int i=x;i>=1;i-=lowbit(i))
ret+=sum[i],ret-=times[i]*p[num].w;
if(ret>=p[num].r) return true;
else return false;
}
int half(int x)
{
int l=1,r=m,mid;
while(l<=r)
{
mid=(l+r)>>1;
if(query(mid,x)==true) r=mid-1;
else l=mid+1;
}
if(l>m) return 0;
return l;
}
int main()
{
//freopen("work.in","r",stdin);
//freopen("work.out","w",stdout);
n=readint();m=readint();
for(int i=1;i<=m;i++)
{
t[i].w=readint();
t[i].num=i;
}
for(int i=1;i<=n;i++)
{
p[i].w=readint();
p[i].r=readint();
p[i].num=i;
}
sort(t+1,t+m+1,comp);
sort(p+1,p+n+1,comp);
for(int i=1;i<=n;i++)
{
while(p[i].w<t[po].w&&po<=m)
{
insert(t[po].num,t[po].w,1);
po++;
}
ans[p[i].num]=half(i);
}
for(int i=1;i<=n;i++) cout<<ans[i]<<" ";//printf("%d ",ans[i]);
return 0;
}