題目描述:
一開始有 n 個非負整數 h[i] (1<=i<=n) ,接下來會進行 m 次操作,第 i 次操作給出乙個數 c[i] ,要求你選出 c[i] 個大於0的數並將它們減去1。
問最多可以進行多少輪操作後無法操作(即沒有 c[i] 個大於0的數)。
輸入格式:
第一行兩個數表示 n 和 m。
第二行 n 個數描述 h[i]。
第三行 m 個數描述c[i]。
輸出格式:
一行表示答案,即最多可以進行多少輪操作後無法操作。
資料範圍:
對於10%的是資料滿足:1<=n,m<=5。
對於另外20%的資料滿足:1<=n<=8;1<=h[i]<=7。
對於50%的資料滿足:1<=n,m<=1000。
對於80%的資料滿足:1<=n,m<=100000。
對於100%的資料滿足:1<=n,m<=1000000 。
解析:
有三種主流做法:平衡樹、二分+貪心、權值線段樹。
先說題解方法二分+貪心(其實很慢...)。做法就是二分答案,然後用貪心驗證。說到這個題的貪心,幾位大佬都沒法證明它的正確性(讀者有興趣可以試著證一下)。具體的貪心就是取最開始前 c[i] 個大的(不管後來是不是前 c[i] 大),如果不夠,那麼就往後面取。就是這樣,我只能說看出來貪心也是一種dp,有時候你知道這樣做是對的,但你就是無法證明它的正確性......
然後說一下權值線段樹。其實就是維護整個序列是單調遞增的。舉個例子:
假設此時c=5,如果直接取前5大的數減去1,那麼整個序列就不滿足單增,所以對於3有多個,我們就只能取前兩個3減1,才能保證序列的單調性。如圖:
於是就變成了:
這樣整個序列就仍然保持單調性了。具體細節詳見**。
至於平衡樹,作為乙個noip蒟蒻,對於noi的演算法當然就無能為力了,不過還是貼一位大佬的**(僅供欣賞)。
**(二分+貪心):
#include using namespace std;
const int max=1001000;
int n,m;
long long h[max],c[max];
long long sum[max],num[max];
inline int get_int()
for(;isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+c-'0';
return x*f;
}inline bool comp(const int &a,const int &b)
inline int check(int k)
for(int i=n;i>=1;i--) sum[i]=num[i]+sum[i+1];
long long ss=0;
for(int i=1;i<=n;i++)
cout<
#include using namespace std;
const int max=1001000;
int n,m;
int h[max];
struct shu;
shu tree[max*4];
inline int get_int()
for(;isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+c-'0';
return x*f;
}inline void update(int root)
inline int modify(int root,int num)
inline void pushdown(int root)
}inline void build(int root,int l,int r) //建樹
int mid=(l+r)>>1;
build(root<<1,l,mid);
build(root<<1|1,mid+1,r);
update(root);
}inline int q(int root,int l,int r,int pos)
inline int find(int root,int l,int r,int num) //尋找
inline void change(int root,int l,int r,int l,int r) //區間修改
pushdown(root);
int mid=(l+r)>>1;
if(l<=mid) change(root<<1,l,mid,l,r);
if(r>mid) change(root<<1|1,mid+1,r,l,r);
update(root);
}int main()
while(isdigit(ch))
return i*f;
}inline uint unit()
const int maxn=1e6+50;
int n,m,a[maxn];
struct nodepool[maxn],*pool=pool,*null=pool,*rt=null;
typedef pairpii;
inline void node::upt()
inline void node::add(int t)
inline void node::pushdown()
inline node* newnode(int v)
inline node* merge(node *x,node *y)else
}inline pii split_sze(node *now,int sz)else
}inline pii split_val(node *now,int v)else
}int main()
sort(a+1,a+n+1);
for(int i=1;i<=n;i++)if(a[i])rt=merge(rt,newnode(a[i]));
for(int i=1;i<=m;i++)else
} printf("%d\n",m);
}
snoi多校模擬賽 1 16 t2
原題 bzoj2900 time limit 10 sec memory limit 512 mb submit 99 solved 59 submit status discuss tk在虐題的同時,也喜歡玩遊戲。現在,有這樣的乙個遊戲,規則是這樣的 先隨機給出乙個數字n,然後你在操場上把1到n的...
NOIP2017模擬A組模擬8 5 序列問題
輸入檔名為seq.in。首先輸入n。接下來輸入n個數,描述序列 a。輸出檔名為seq.out。輸出一行乙個整數代表答案。7 0 35 40 45 56 65 94 對於30 的資料,n 5000 對於60 的資料,n 50000 對於100 的資料,n 500000,0 a i 10 9 這題還是很...
NOIP校內模擬 T2 字胡串(分治)
lst神仙 這是他的做法 吊了標算 對於這種有多少區間滿足要求的 我們套路的用分治做 每次都統計左端點在左半邊 右端點在右半邊的個數 設f i 表示當前點到中間分割點的最大值,g i 表示當前點到中間分割點的或和 我們發現 g i f i 所以只需找到g i f i 的區間就好 然後f肯定是單調遞增...