1. 程式人生 > >[NOIP模擬][資料結構][二分]Work

[NOIP模擬][資料結構][二分]Work

題目描述:
題目背景: 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; }