1. 程式人生 > >Codeforces 980D. Perfect Groups

Codeforces 980D. Perfect Groups

getchar() getc family sort perfect 要求 因數 染色 return

http://codeforces.com/contest/980/problem/D

大致題意,設F(S)表示在集合S中把元素劃分成若幹組,使得每組內元素兩兩相乘的結果的都是完全平方數的最小劃分組數

對於給定的序列A,對於每一個k = 1..n,分別求出在A的所有子串[l, r]中有多少滿足F(A[l..r]) = k

n <= 5000, abs(A[i]) <= 10^9

先考慮如何求出F(S),對於一個滿足要求的組,可以發現對組內元素分解質因數後,每一個質數出現次數的奇偶性相同;

證明 : 如果兩數相乘是平方數,設這個數為p1^k1*p2^k2*..*pn*kn,必然有所有k % 2 = 0,當且僅當只有奇偶性相同的兩個數相加才能變成偶數,所以每一個分解質因數後每一個質數出現次數的奇偶性相同

通過這個性質,就可以推導出本題的很多做法:

做法1:考慮出現次數為偶數的質因子本身就可以構成平方數,所以導致分組不合法的只可能是出現次數為奇數的質因子,考慮對於序列中所有數分解質因數,把所有出現次數為奇數的質因子放進一個vector中

對於每一個數產生的vector,用map來給他們染色,相同的vector對應的數染成一個顏色,如果說一些數對應的顏色相同,那麽說明所有數的奇數質因子在兩兩相乘的時候都可以消去,即可以把這些數分成一組,那麽問題就轉變為求區間內不同的顏色數,直接掃一遍即可

做法2:還是考慮偶數因子是沒有用的,實際上只需要關心每一個質因子的出現次數在模2意義下的奇偶性,所以大可以把所有數除去他們的平方因子,離散後做一遍區間數顏色即可

做法3:由做法1可以推導出,對於合法的組內的元素,他們出現次數為奇數的質因子都是相同的,那麽如果說A * B為完全平方數, B * C 為完全平方數,說明A,B的奇數質因子集合相同,BC的奇數質因子集合相同,所以AC的奇數質因子集合也相同

。所以當滿足AB是完全平方數,BC是完全平方數時,AC也是完全平方數,這個東西具有傳遞性,考慮對於每一個數A[i],只需要找到其前面最後一個能和他合並的數pre[i],對於每一個區間,答案是滿足pre[i] < 左端點的i的數量

對於上述所有做法,都要記得特判0!!!

技術分享圖片
/*program by mangoyang*/
#include<bits/stdc++.h>
#define
inf (0x7f7f7f7f) #define Max(a, b) ((a) > (b) ? (a) : (b)) #define Min(a, b) ((a) < (b) ? (a) : (b)) typedef long long ll; using namespace std; template <class T> inline void read(T &x){ int f = 0, ch = 0; x = 0; for(; !isdigit(ch); ch = getchar()) if(ch == -) f = 1; for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - 48; if(f) x = -x; } #define N (100005) #define int ll struct Point{ int x, id; } e[N]; int a[N], buf[N], Ans[N], n, col, f0; inline bool cmp(Point A, Point B){ return A.x < B.x; } inline int change(int x){ int res = x; for(int i = 2; i * i <= abs(x); i++) while(res % (i * i) == 0) res /= i * i; return res; } main(){ read(n); for(int i = 1; i <= n; i++) read(a[i]), a[i] = change(a[i]); for(int i = 1; i <= n; i++) e[i].x = a[i], e[i].id = i; sort(e + 1, e + n + 1, cmp); a[e[1].id] = ++col; if(e[1].x == 0) f0 = 1; for(int i = 2; i <= n; a[e[i++].id] = col){ if(e[i].x > e[i-1].x) col++; if(e[i].x == 0) f0 = col; } for(int i = 1; i <= n; i++){ int res = 0; for(int j = i; j <= n; j++){ if(!buf[a[j]] && a[j] != f0) res++; buf[a[j]]++; if(!res) Ans[1]++; else Ans[res]++; } for(int j = i; j <= n; j++) buf[a[j]]--; } for(int i = 1; i <= n; i++) cout << Ans[i] << " "; return 0; }
萌萌噠的代碼>.<

Codeforces 980D. Perfect Groups