10 6NOIP普及模擬 MATH 列舉法

2021-07-26 06:58:15 字數 1375 閱讀 3401

乙個數列任意刪k個數,是得數列中最大的差+最小的差最小

暴搜+剪枝。

用類似排列組合的方式,暴搜刪或不刪

剪枝就是看看剩下的數,如果還小於k,則退出

這是suzejia大神教我的:

令m=n-k;(即數列長度)

排序一遍

因為要求最小,並且最大差即為最大數-最小數

所以刪後的數列是乙個區間,設l為左,r為右。

l=1~k+1;因為r最多為n,長度為m,n-(k+1)+1=m

r=l+m-1;由r-l+1=m變形而來

然後列舉,m=a[r]-a[l],m為相鄰數中差最小的(暴力)

ans=min(m+m,ans)

時間超限必定是在l的迴圈和列舉m的迴圈中出現的,又因為l是必要的,所以

列舉m時不能暴力。

因此,我用了rmq

c++(pascal選手對不起)

#include 

#include

#include

#include

#include

#include

using

namespace

std;

int n,k,m,ans;

int v[200001];

int cha[200001];//cha[i]表示v[i+1]-v[i]

int f[200001][21];//rmq,f[i][j]表示i到i+2^j-1中最小值

int main()

bool cmp(int,int);

make_heap(v+1,v+n+1,cmp);//建堆

sort_heap(v+1,v+n+1,cmp);//堆排序

cha[0]=int_max;

for(i=1;i<=n-1;i++)

cha[i]=v[i+1]-v[i];//cha[i]表示v[i+1]與v[i]的差

void rmq();

rmq();//預處理

m=n-k;

ans=int_max;

int ask(int,int);//表示一段區間的最小數

for(l=1;l<=k+1;l++)

printf("%d\n",ans);

return0;}

bool cmp(int a,int b)

}} int ask(int l,int r)

有些題目,不要想複雜,要化繁為簡,才能找到正解。

NOIP2012模擬10 6 購買

description 小n 最近迷上了購物每天都讓小a 和小t 陪她逛街拿東西。最近商店出了這樣的乙個 活動 買東西送積分,就是買一件物品,送當前物品的積分ci 當前的倍率,初始倍率是1 input 第一行有乙個整數n表示要買的種類。接下來n行每行2個整數ki,ci表示數量和積分 接下來一行有乙個...

NOIP2012模擬10 6 購買

description 小n 最近迷上了購物每天都讓小a 和小t 陪她逛街拿東西。最近商店出了這樣的乙個 活動 買東西送積分,就是買一件物品,送當前物品的積分ci 當前的倍率,初始倍率是1 當倍率是i 的時候,如果你買的物品等於ti 個,那麼倍率將加1.最多積分的人可以得到超限 量版的圓神手辦。小n...

NOIP2012模擬10 6 填充棋盤

description 橫一劃豎一劃,橫一劃豎一劃 小r畫出了乙個n m的棋盤。由於noip快要到了,小r有了乙個奇妙的想法。在棋盤的每乙個小方格中填入n,o,i,p這4個字母中的乙個,若棋盤中每乙個2 2的小棋盤中都有n,o,i,p這4個字母,小r就認為這個棋盤是幸運棋盤。小r想知道一共有多少種不...