洛谷P3940 分組

2022-03-16 23:58:13 字數 1605 閱讀 9225

好題+細節題

答案字典序要求最小,所以考慮倒敘列舉,對於當前一組需要盡量多的加東西,因為後面組選的數越多,前面的選擇機會越多

列舉序列列舉值域,這是這道題的關鍵

\(k=1\):倒敘列舉到\(i\),此時只需判斷當前組中的數是否有加\(a_i\)等於完全平方數的;可以\(o(n)\)列舉,但顯然可以更優:列舉所有的完全平方數,對於之前的數開桶記錄即可,這樣做的複雜度為完全平方數的個數,可以發現最大為512,可以通過這部分資料

\(k=2\):同理倒敘列舉到\(i\),此時分兩種情況:

一般情況下,\(a_i\)第一次出現在這一組中;「如果有與\(a_i\)成為完全平方數的數,那麼它們倆不能在同一邊」->「兩個點不能在同一邊」,這是不是很眼熟?就是擴充套件域並查集好題(裸題)關押罪犯,所以直接套用這個做法即可;優化:直接列舉序列仍然是\(o(n^2)\)的,所以令\(f_i\)表示與\(i\)為友的集合,\(f_\)表示與\(i\)為敵的集合,直接合併並查集就好了

\(a_i\)多次出現且\(2\times a_i\)為完全平方數,上面的值域並查集並不能很好的處理這種自己和自己的關係,所以需要特判

細節:上面的1無法考慮到另乙個數自己和自己成完全平方的情況,需要特殊處理,在**中有注釋(如果沒有考慮到會錯後面幾個點)

全部寫清楚就是這樣的。。。

#include#define n 150005

#define min(x,y) ((x)<(y)?(x):(y))

#define max(x,y) ((x)>(y)?(x):(y))

#define re register

using namespace std;

typedef long long ll;

int temp=512,c=512*512+1;

int n,k,a[n],ct[n],tot;

bool exist[n<<2];

template void read(t &x)

bool check1(int x)

return 1;

}void solve1()

} printf("%d\n",tot+1);

for(int i=tot;i>=1;--i) printf("%d ",ct[i]);

printf("\n");

}int fa[n<<4],vis[n<<4];

bool tag[n<<4];

int find(int x)

int merge(int x,int y)

void solve2()}}

} else for(int j=temp;j>=1;--j)

if(no) break;

} if(no)

vis[a[i]]++;

} printf("%d\n",tot+1);

for(int i=tot;i>=1;--i) printf("%d ",ct[i]);

printf("\n");

}int main()

洛谷P3940 分組(並查集)(暴力)

首先發現資料限制了只有k 1 k 1k 1和k 2k 2 k 2的情況,而且值域不是很大,或許可以暴力列舉平方根。考慮k 1 k 1k 1的情況,顯然直接列舉平方根,把不能同組出現的數標記一下就行了。注意我們需要最小化分界的字典序,所以實際上是將字尾劃分得盡量長而已,倒著列舉即可。考慮k 2 k 2...

無聊的序列 洛谷p3940

無聊的yyb總喜歡搞出一些正常人無法搞出的東西。有一天,無聊的yyb想出了一道無聊的題 無聊的數列。k峰 這題不是傻x題嗎 維護乙個數列,支援兩種操作 1 1 l r k d 給出乙個長度等於r l 1的等差數列,首項為k,公差為d,並將它對應加到a l a r 的每乙個數上。即 令a l a l ...

洛谷 P4447分組

大致想法是用乙個佇列記錄當前正在進行中分組的起始位置,並記錄當前分組數,若掃瞄到的下乙個數的個數少於當前分組數,則代表當前有一定數量的分組需要就此停止,按照開始順序依次出佇列即可 include include include include include include include incl...