NOIP模擬 11 6 T2 序列操作

2021-08-10 10:32:02 字數 3086 閱讀 9250

題目描述:

一開始有 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肯定是單調遞增...