好題+細節題
答案字典序要求最小,所以考慮倒敘列舉,對於當前一組需要盡量多的加東西,因為後面組選的數越多,前面的選擇機會越多
化列舉序列為列舉值域,這是這道題的關鍵
\(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...