2021-06-19 集訓題解
阿新 • • 發佈:2021-06-20
T1 區間第 k 小
Description
給出一個長度為 \(n\) 的序列,給出 \(w\),有 \(q\) 次查詢,每次查詢給出 \(l,r,k\),求出忽視掉區間出現次數 \(\ge w\) 的數之後第 \(k\) 大是多少,如沒有 \(k\) 個則輸出 \(n\)。
\(n\le 10^5,0\le a_i<n\)
Solution
考慮分塊。我們可以先提前處理出 \(s1_{i,j,k}\) 和 \(s2_{i,j}\),\(s1_{i,j,k}\) 表示區間上第 \(i\) 個塊到第 \(j\) 個塊第 \(k\) 個值域塊出現次數 \(\le w\) 的數的出現次數之和,\(s2_{i,j}\)
然後查詢的時候就可以算出每個值域塊的個數,以及每個數的出現次數,用平衡樹上查詢第 \(k\) 大的方法查就好了。
時空複雜度均為 \(\Theta(n\log n)\)。
Code
#include <bits/stdc++.h> using namespace std; #define Int register int #define MAXN 100005 #define MAXM 355 template <typename T> void read (T &x){char c = getchar ();x = 0;int f = 1;while (c < '0' || c > '9') f = (c == '-' ? -1 : 1),c = getchar ();while (c >= '0' && c <= '9') x = x * 10 + c - '0',c = getchar ();x *= f;} template <typename T,typename ... Args> void read (T &x,Args& ... args){read (x),read (args...);} template <typename T> void write (T x){if (x < 0) x = -x,putchar ('-');if (x > 9) write (x / 10);putchar (x % 10 + '0');} template <typename T> void chkmax (T &a,T b){a = max (a,b);} template <typename T> void chkmin (T &a,T b){a = min (a,b);} int n,w,T,siz,cnt,type,a[MAXN],t[MAXN],t1[MAXM],bel[MAXN],col[MAXN],cor[MAXN],s1[MAXM][MAXM][MAXM],s2[MAXM][MAXN]; void buildit (){ siz = sqrt (n),cnt = (n - 1) / siz + 1; for (Int i = 1;i <= n;++ i) bel[i] = (i - 1) / siz + 1,cor[bel[i]] = i,col[bel[i]] = !col[bel[i]] ? i : col[bel[i]]; for (Int j = 1;j <= cnt;++ j) for (Int i = 1;i <= cor[j];++ i) s2[j][a[i]] ++; for (Int i = 1;i <= cnt;++ i){ for (Int j = i;j <= cnt;++ j){ for (Int k = 1;k <= cnt;++ k) s1[i][j][k] = s1[i][j - 1][k]; for (Int k = col[j];k <= cor[j];++ k){ ++ t[a[k]]; if (t[a[k]] < w) s1[i][j][bel[a[k]]] ++; else if (t[a[k]] == w) s1[i][j][bel[a[k]]] -= w - 1; } } for (Int j = 1;j <= n;++ j) t[j] = 0; } } int query (int l,int r,int k){ int res = n + 1; if (bel[l] == bel[r]){ for (Int i = 1;i <= cnt;++ i) t1[i] = 0; for (Int i = l;i <= r;++ i){ t[a[i]] ++; if (t[a[i]] < w) t1[bel[a[i]]] ++; else if (t[a[i]] == w) t1[bel[a[i]]] -= w - 1; } for (Int i = 1;i <= cnt;++ i) if (t1[i] >= k){ for (Int j = col[i];j <= cor[i];++ j) if (t[j] >= w) continue; else if (t[j] >= k){ res = j; break; } else k -= t[j]; break; } else k -= t1[i]; for (Int i = l;i <= r;++ i) t[a[i]] --; return res - 1; } int qL = bel[l],qR = bel[r]; for (Int i = 1;i <= cnt;++ i) t1[i] = s1[qL + 1][qR - 1][i]; for (Int i = l,h;i <= cor[qL];++ i){ t[a[i]] ++; if ((h = t[a[i]] + s2[qR - 1][a[i]] - s2[qL][a[i]]) < w) t1[bel[a[i]]] ++; else if (h == w) t1[bel[a[i]]] -= w - 1; } for (Int i = col[qR],h;i <= r;++ i){ t[a[i]] ++; if ((h = t[a[i]] + s2[qR - 1][a[i]] - s2[qL][a[i]]) < w) t1[bel[a[i]]] ++; else if (h == w) t1[bel[a[i]]] -= w - 1; } for (Int i = 1;i <= cnt;++ i) if (t1[i] >= k){ for (Int j = col[i];j <= cor[i];++ j){ int h = t[j] + s2[qR - 1][j] - s2[qL][j]; if (h >= w) continue; else if (h >= k){res = j;break;} else k -= h; } break; } else k -= t1[i]; for (Int i = l;i <= cor[qL];++ i) t[a[i]] --; for (Int i = col[qR];i <= r;++ i) t[a[i]] --; return res - 1; } signed main(){ read (n,w,T,type),++ w; for (Int i = 1;i <= n;++ i) read (a[i]),++ a[i]; buildit ();int lst = 0; while (T --> 0){ int l,r,k;read (l,r,k); l ^= lst * type,r ^= lst * type,k ^= lst * type; write (lst = query (l,r,k)),putchar ('\n'); } return 0; }
T2 求和
Description
Solution
發現式子可以化成:
\[\sum_{x=1}^{n} \sum_{d=1}^{k} f_d(x)(2\sum_{i=1}^{\lfloor\frac{n}{x}\rfloor} \varphi(i)-1) \]前面那個可以 \(\text{Powerful Number}\) 做,後面的那個可以杜教篩。擬合函式用 \(\mu\) 就可以了。
複雜度顯然是 \(\Theta(n^{2/3})\) 。
Code
#include <bits/stdc++.h> using namespace std; #define Int register long long #define mod 1073741824 #define int long long #define MAXN 5000005 template <typename T> void read (T &x){char c = getchar ();x = 0;int f = 1;while (c < '0' || c > '9') f = (c == '-' ? -1 : 1),c = getchar ();while (c >= '0' && c <= '9') x = x * 10 + c - '0',c = getchar ();x *= f;} template <typename T,typename ... Args> void read (T &x,Args& ... args){read (x),read (args...);} template <typename T> void write (T x){if (x < 0) x = -x,putchar ('-');if (x > 9) write (x / 10);putchar (x % 10 + '0');} template <typename T> void chkmax (T &a,T b){a = max (a,b);} template <typename T> void chkmin (T &a,T b){a = min (a,b);} int mul (int a,int b){return 1ll * a * b % mod;} int dec (int a,int b){return a >= b ? a - b : a + mod - b;} int add (int a,int b){return a + b >= mod ? a + b - mod : a + b;} int qkpow (int a,int b){ int res = 1;for (;b;b >>= 1,a = mul (a,a)) if (b & 1) res = mul (res,a); return res; } void Add (int &a,int b){a = add (a,b);} int upd (int x){return x < 0 ? x + mod : x;} #define lim 5e6 int N,K; bool vis[MAXN]; int sq,cnt,ptot,pf[MAXN],mu[MAXN],mn[MAXN],mx[MAXN],dF[MAXN],id1[MAXN],id2[MAXN],phi[MAXN],dmu[MAXN],num[MAXN],dphi[MAXN],prem[MAXN],prep[MAXN],preF[MAXN],idsum[MAXN],prime[MAXN]; int getF (int n){ if (n == 1) return K; if (mx[n] > K) return 0; return mul (upd (idsum[n] & 1 ? -1 : 1),K - mx[n] + 1); } int getSum (int n){ if (n & 1) return mul ((n + 1) / 2 % mod,n % mod); else return mul (n / 2 % mod,(n + 1) % mod); } void Euler (int up){ mu[1] = phi[1] = 1; for (Int i = 2;i <= up;++ i){ if (!vis[i]) prime[++ ptot] = i,mx[i] = mn[i] = idsum[i] = 1,mu[i] = -1,phi[i] = i - 1; for (Int j = 1;j <= ptot && i * prime[j] <= up;++ j){ vis[i * prime[j]] = 1,idsum[i * prime[j]] = idsum[i] + 1; if (i % prime[j]) mx[i * prime[j]] = max (mx[i],1ll),mn[i * prime[j]] = 1, mu[i * prime[j]] = -mu[i],phi[i * prime[j]] = phi[i] * (prime[j] - 1); else{ mx[i * prime[j]] = max (mx[i],mn[i] + 1),mn[i * prime[j]] = mn[i] + 1; phi[i * prime[j]] = phi[i] * prime[j]; break; } } } for (Int i = 1;i <= up;++ i) prem[i] = add (prem[i - 1],upd (mu[i])),prep[i] = add (prep[i - 1],phi[i]),preF[i] = add (preF[i - 1],getF (i)); } int getmu (int n){ if (n <= lim) return prem[n]; int pos = n <= sq ? id1[n] : id2[N / n]; if (~dmu[pos]) return dmu[pos]; int &res = dmu[pos] = 1; for (Int l = 2,r;l <= n;l = r + 1) r = n / (n / l),res = dec (res,mul (r - l + 1,getmu (n / l))); return res; } int getphi (int n){ if (n <= lim) return prep[n]; int pos = n <= sq ? id1[n] : id2[N / n]; if (~dphi[pos]) return dphi[pos]; int &res = dphi[pos] = 1ll * n * (n + 1) / 2 % mod; for (Int l = 2,r;l <= n;l = r + 1) r = n / (n / l),res = dec (res,mul (r - l + 1,getphi (n / l))); return res; } #define inf 1e9 #define pii pair<int,int> int tot; pii pwer[1000005]; void dfs (int now,int n,int down,int up){ pwer[++ tot].first = n; if (up == inf) pwer[tot].second = max (K - down,0ll) + min (down,K) / 2; else pwer[tot].second = min (up,K) / 2; for (Int i = now + 1;i <= ptot && n <= N / prime[i] / prime[i];++ i) for (Int pw = prime[i] * prime[i],e = 2;n * pw <= N;pw *= prime[i],e ++){ if (e & 1) dfs (i,n * pw,down,min (up,e)); else dfs (i,n * pw,max (down,e),up); } } int getf (int n){ if (n <= lim) return preF[n]; int pos = n <= sq ? id1[n] : id2[N / n]; if (~dF[pos]) return dF[pos]; int &res = dF[pos] = 0; for (Int l = 1,r;l <= tot && num[l] <= n;l = r + 1) r = n / (n / num[l]), r = upper_bound (num + 1,num + tot + 1,r) - num - 1, Add (res,mul (dec (pf[r],pf[l - 1]),getmu (n / num[l]))); return res; } signed main(){ read (N,K),sq = sqrt (N),Euler (min (N,(int)lim)); for (Int l = 1,r;l <= N;l = r + 1){ r = N / (N / l); if (N / l <= sq) id1[N / l] = ++ cnt; else id2[N / (N / l)] = ++ cnt; } for (Int i = 1;i <= cnt;++ i) dF[i] = dmu[i] = dphi[i] = -1; dfs (0,1,0,inf),sort (pwer + 1,pwer + tot + 1); for (Int i = 1;i <= tot;++ i) num[i] = pwer[i].first,pf[i] = add (pf[i - 1],pwer[i].second); int ans = 0; for (Int l = 1,r,lst = 0;l <= N;l = r + 1){ r = N / (N / l);int t = getphi (N / l),h = getf (r); Add (ans,mul (dec (h,lst),dec (add (t,t),1))),lst = h; } write (ans),putchar ('\n'); return 0; }
T3
Description
Solution
Code
#include <bits/stdc++.h>
using namespace std;
#define Int register int
#define MAXN 1000005
template <typename T> void read (T &x){char c = getchar ();x = 0;int f = 1;while (c < '0' || c > '9') f = (c == '-' ? -1 : 1),c = getchar ();while (c >= '0' && c <= '9') x = x * 10 + c - '0',c = getchar ();x *= f;}
template <typename T,typename ... Args> void read (T &x,Args& ... args){read (x),read (args...);}
template <typename T> void write (T x){if (x < 0) x = -x,putchar ('-');if (x > 9) write (x / 10);putchar (x % 10 + '0');}
template <typename T> void chkmax (T &a,T b){a = max (a,b);}
template <typename T> void chkmin (T &a,T b){a = min (a,b);}
vector <int> G[MAXN];
int n,len1,len2,f[MAXN],s[MAXN],t[MAXN];
void dfs (int u,int fa){
for (Int v : G[u]) if (v ^ fa) dfs (v,u),f[u] -= f[v];
int now = f[u] * (u > fa ? 1 : -1);
for (Int v : G[u]) if (v ^ fa) now += f[v] * (u > v ? 1 : -1);
if (now > 0) for (Int i = 1;i <= now;++ i) t[++ len1] = u;
else for (Int i = 1;i <= -now;++ i) s[++ len2] = u;
}
signed main(){
read (n);
for (Int i = 1;i <= n;++ i) read (f[i]);
for (Int i = 2,u,v;i <= n;++ i) read (u,v),G[u].push_back (v),G[v].push_back (u);
dfs (1,0),sort (s + 1,s + len2 + 1),sort (t + 1,t + len1 + 1);
write (len1),putchar ('\n');
for (Int i = 1;i <= len1;++ i) write (s[i]),putchar (' '),write (t[i]),putchar ('\n');
return 0;
}