[考試總結]ZROI-21-NOIP衝刺-TEST11 總結
#T1 因子差
Time Limit: 1s | Memory Limit: 512MiB
#題意簡述
認為一個數是有趣的,當且僅當:
- 這個數是一個正整數;
- 這個數至少有 \(4\) 個不同的因子;
- 這個數的任意兩個因子之間的差都不小於 \(n(n\leq10^5)\) 。
問最小的有趣的數是多少。多組資料。
#大體思路
首先一個數 \(x\) 必然有兩個因子 \(1\) 和 \(x\),於是我們只需要讓第一個因數 \(p_1\) 是大於等於 \(n+1\) 的第一個質數,\(p_2\) 是大於等於 \(p_1+1\) 的第一個質數,不難證明這樣必然是最優的(考慮一個非質數的因子),於是我們可以提前預處理出質數,然後 lower_bound
#Code
const int N = 500010; const int INF = 0x3fffffff; template <typename T> inline void read(T &x) { x = 0; int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = x * 10 + c - '0'; x *= f; } int prm[N], nprm[N], ncnt; inline void euler(int x) { for (int i = 2; i <= x; ++ i) { if (!nprm[i]) prm[++ ncnt] = i; for (int j = 1; j <= ncnt; ++ j) { if (prm[j] * i > x) break; nprm[i * prm[j]] = 1; if (!(i % prm[j])) break; } } } int t, n; #define lb(l, len, x) lower_bound(l + 1, l + len + 1, x) int main() { euler(5e5); read(t); while (t --) { read(n); int pos1 = lb(prm, ncnt, n + 1) - prm; int prm1 = prm[pos1]; int pos2 = lb(prm, ncnt, prm1 + n) - prm; int prm2 = prm[pos2]; printf("%lld\n", 1ll * prm1 * prm2); } return 0; }
#T2 生成樹
Time Limit: 1s | Memory Limit: 512MiB
#題意簡述
給定一個 \(n(n\leq1000)\) 個點的完全圖,每次刪去一個生成樹,問最多能刪多少次,並給出方案。
\(t(t\leq500)\) 組資料,保證滿足 \(\sum n\leq1000\).
#大體思路
構造題,具體見程式碼。
#Code
const int N = 100010; const int INF = 0x3fffffff; template <typename T> inline void read(T &x) { x = 0; int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = x * 10 + c - '0'; x *= f; } int t, n, a[N]; inline void solve() { int mid = 1 + n >> 1, l = mid, r = mid + 1; for (int i = 1; i < n; ++ i) { printf("%d %d\n", a[l], a[r]); if (i & 1) -- l; else ++ r; } } inline void change() { for (int i = n + 1; i > 1; -- i) a[i] = a[i - 1]; a[1] = a[n + 1]; } int main() { read(t); for (int i = 1; i <= t; ++ i) { read(n); printf("Case #%d: %d\n", i, n / 2); for (int i = 1; i <= n; ++ i) a[i] = i; for (int k = 1; k <= n / 2; ++ k) solve(), change(); } return 0; }
#T3 劃分樹
Time Limit: 3s | Memory Limit: 512MiB
#題意簡述
給定一棵 \(n(n\leq10^5)\) 的樹,每個節點有一個權值 \(w_i(w_i\leq10^9)\),給定 \(K(K\leq n)\),要求將整棵樹通過斷開 \(K-1\) 條邊劃分為 \(K\) 部分,使得到的森林的權值最小。
定義一棵樹的權值為樹上所有的節點的權值的和,一個森林的權值為森林中的所有樹的權值中的最大值。
\(t(t\leq10^5)\) 組資料,保證 \(\sum n\leq2\cdot10^5\).
#大體思路
要求最大值最小,直接二分不虧,現在來考慮如何對於 \(x\) 進行判定。
設 \(f_i\) 表示以 \(i\) 為根的子樹內滿足條件至少需要斷開多少條邊,\(g_i\) 表示以 \(i\) 為根的子樹與 \(i\) 相連的連通快的大小,然後對於每個 \(i\),貪心地選其中 \(g\) 小的一定更優。
於是直接 sort()
後 DP 即可,時間複雜度為 \(O(n\log^2n)\).
#Code
#define ll long long
#define mset(l, x) memset(l, x, sizeof(l))
const int N = 300010;
const int INF = 0x3fffffff;
template <typename T> inline void read(T &x) {
x = 0; int f = 1; char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
x *= f;
}
struct Edge {int u, v, nxt;} e[N << 1];
int t, k, n, w[N], head[N], ecnt(1), f[N]; ll sum, siz[N];
vector <ll> all_siz[N];
inline void reset() {mset(head, 0); ecnt = 1, sum = 0;}
inline void add_edge(int u, int v) {
e[ecnt].u = u, e[ecnt].v = v;
e[ecnt].nxt = head[u], head[u] = ecnt ++;
}
void solve(int x, int fa, ll lmt) {
f[x] = 0, siz[x] = 0; all_siz[x].clear();
int cnt = 0; siz[x] = w[x];
for (int i = head[x]; i; i = e[i].nxt) {
if (e[i].v == fa) continue;
solve(e[i].v, x, lmt); ++ cnt;
all_siz[x].push_back(siz[e[i].v]);
f[x] += f[e[i].v];
}
sort(all_siz[x].begin(), all_siz[x].end());
for (auto k : all_siz[x]) {
if (siz[x] + k <= lmt) siz[x] += k, -- cnt;
else break;
}
f[x] += cnt;
}
inline bool check(ll x) {
for (int i = 1; i <= n; ++ i) if (x < w[i]) return false;
solve(1, 0, x); return f[1] <= k - 1;
}
void MAIN() {
read(n), read(k); reset();
for (int i = 1; i < n; ++ i) {
int u, v; read(u), read(v);
add_edge(u, v), add_edge(v, u);
}
for (int i = 1; i <= n; ++ i) read(w[i]), sum += w[i];
ll l = 0, r = sum, res = sum;
while (l <= r) {
ll mid = l + r >> 1;
if (check(mid)) res = mid, r = mid - 1;
else l = mid + 1;
}
printf("%lld\n", res);
}
int main() {read(t); for (int i = 1; i <= t; ++ i) {printf("Case #%d: ", i); MAIN();} return 0;}
#T4
巨大惡心的可持久化陣列維護分塊的字串題,咕咕咕~